src/glipt@runner.erl

-module(glipt@runner).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/glipt/runner.gleam").
-export([run/1]).
-export_type([run_error/0, run_options/0]).

-type run_error() :: {file_error, simplifile:file_error()} |
    {build_error, binary()} |
    {run_error, binary()}.

-type run_options() :: {run_options,
        binary(),
        glipt@target:target(),
        binary(),
        list(binary())}.

-file("src/glipt/runner.gleam", 60).
-spec setup_project(
    binary(),
    binary(),
    binary(),
    glipt@parser:script_meta(),
    glipt@target:target(),
    binary(),
    binary()
) -> {ok, nil} | {error, run_error()}.
setup_project(Key, Script_path, Source, Meta, T, Function, Module_name) ->
    Project_dir = glipt@internal@cache:cached_project_path(Key),
    Src_dir = <<Project_dir/binary, "/src"/utf8>>,
    gleam@result:'try'(
        begin
            _pipe = glipt@internal@cache:ensure_cache_dir(),
            gleam@result:map_error(
                _pipe,
                fun(Field@0) -> {file_error, Field@0} end
            )
        end,
        fun(_) ->
            gleam@result:'try'(
                begin
                    _pipe@1 = simplifile:create_directory_all(Src_dir),
                    gleam@result:map_error(
                        _pipe@1,
                        fun(Field@0) -> {file_error, Field@0} end
                    )
                end,
                fun(_) ->
                    Script_dir = glipt@internal@path:dirname(Script_path),
                    Toml_content = glipt@internal@toml:generate_runtime_toml(
                        Meta,
                        T,
                        Script_dir
                    ),
                    gleam@result:'try'(
                        begin
                            _pipe@2 = simplifile:write(
                                <<Project_dir/binary, "/gleam.toml"/utf8>>,
                                Toml_content
                            ),
                            gleam@result:map_error(
                                _pipe@2,
                                fun(Field@0) -> {file_error, Field@0} end
                            )
                        end,
                        fun(_) ->
                            Dest = <<<<<<Src_dir/binary, "/"/utf8>>/binary,
                                    Module_name/binary>>/binary,
                                ".gleam"/utf8>>,
                            Clean_source = glipt@parser:strip_directives(Source),
                            gleam@result:'try'(
                                begin
                                    _pipe@3 = simplifile:write(
                                        Dest,
                                        Clean_source
                                    ),
                                    gleam@result:map_error(
                                        _pipe@3,
                                        fun(Field@0) -> {file_error, Field@0} end
                                    )
                                end,
                                fun(_) -> gleam@result:'try'(case Function of
                                            <<"main"/utf8>> ->
                                                {ok, nil};

                                            Func ->
                                                Entry_source = <<<<<<<<<<<<"import "/utf8,
                                                                        Module_name/binary>>/binary,
                                                                    "\n\npub fn main() {\n  "/utf8>>/binary,
                                                                Module_name/binary>>/binary,
                                                            "."/utf8>>/binary,
                                                        Func/binary>>/binary,
                                                    "()\n}\n"/utf8>>,
                                                _pipe@4 = simplifile:write(
                                                    <<Src_dir/binary,
                                                        "/glipt_entry.gleam"/utf8>>,
                                                    Entry_source
                                                ),
                                                gleam@result:map_error(
                                                    _pipe@4,
                                                    fun(Field@0) -> {file_error, Field@0} end
                                                )
                                        end, fun(_) ->
                                            gleam@result:'try'(
                                                begin
                                                    _pipe@5 = shellout:command(
                                                        <<"gleam"/utf8>>,
                                                        [<<"deps"/utf8>>,
                                                            <<"download"/utf8>>],
                                                        Project_dir,
                                                        [let_be_stderr]
                                                    ),
                                                    gleam@result:map_error(
                                                        _pipe@5,
                                                        fun(E) ->
                                                            {build_error,
                                                                <<"deps download failed: "/utf8,
                                                                    (erlang:element(
                                                                        2,
                                                                        E
                                                                    ))/binary>>}
                                                        end
                                                    )
                                                end,
                                                fun(_) ->
                                                    _pipe@6 = shellout:command(
                                                        <<"gleam"/utf8>>,
                                                        [<<"build"/utf8>>,
                                                            <<"--target"/utf8>>,
                                                            glipt@target:to_string(
                                                                T
                                                            )],
                                                        Project_dir,
                                                        [let_be_stderr]
                                                    ),
                                                    _pipe@7 = gleam@result:map_error(
                                                        _pipe@6,
                                                        fun(E@1) ->
                                                            {build_error,
                                                                erlang:element(
                                                                    2,
                                                                    E@1
                                                                )}
                                                        end
                                                    ),
                                                    gleam@result:map(
                                                        _pipe@7,
                                                        fun(_) -> nil end
                                                    )
                                                end
                                            )
                                        end) end
                            )
                        end
                    )
                end
            )
        end
    ).

-file("src/glipt/runner.gleam", 123).
-spec execute(binary(), binary(), glipt@target:target(), list(binary())) -> {ok,
        binary()} |
    {error, run_error()}.
execute(Key, Module_name, T, Script_args) ->
    Project_dir = glipt@internal@cache:cached_project_path(Key),
    Base_args = [<<"run"/utf8>>,
        <<"--target"/utf8>>,
        glipt@target:to_string(T),
        <<"-m"/utf8>>,
        Module_name],
    Args = case Script_args of
        [] ->
            Base_args;

        _ ->
            lists:append(Base_args, [<<"--"/utf8>> | Script_args])
    end,
    _pipe = shellout:command(
        <<"gleam"/utf8>>,
        Args,
        Project_dir,
        [let_be_stderr]
    ),
    gleam@result:map_error(
        _pipe,
        fun(E) -> {run_error, erlang:element(2, E)} end
    ).

-file("src/glipt/runner.gleam", 185).
-spec resolve_path_in_constraint(binary(), binary()) -> binary().
resolve_path_in_constraint(Constraint, Project_root) ->
    case gleam@string:split_once(Constraint, <<"path"/utf8>>) of
        {ok, {Before, After}} ->
            case gleam@string:split_once(After, <<"\""/utf8>>) of
                {ok, {Middle, Rest}} ->
                    case gleam@string:split_once(Rest, <<"\""/utf8>>) of
                        {ok, {Rel_path, End}} ->
                            Abs_path = case gleam_stdlib:string_starts_with(
                                Rel_path,
                                <<"/"/utf8>>
                            ) of
                                true ->
                                    Rel_path;

                                false ->
                                    <<<<Project_root/binary, "/"/utf8>>/binary,
                                        Rel_path/binary>>
                            end,
                            <<<<<<<<<<<<Before/binary, "path"/utf8>>/binary,
                                                Middle/binary>>/binary,
                                            "\""/utf8>>/binary,
                                        Abs_path/binary>>/binary,
                                    "\""/utf8>>/binary,
                                End/binary>>;

                        {error, nil} ->
                            Constraint
                    end;

                {error, nil} ->
                    Constraint
            end;

        {error, nil} ->
            Constraint
    end.

-file("src/glipt/runner.gleam", 170).
-spec resolve_relative_paths(list(glipt@parser:dependency()), binary()) -> list(glipt@parser:dependency()).
resolve_relative_paths(Deps, Project_root) ->
    gleam@list:map(
        Deps,
        fun(Dep) ->
            case gleam_stdlib:contains_string(
                erlang:element(3, Dep),
                <<"path"/utf8>>
            ) of
                true ->
                    Resolved = resolve_path_in_constraint(
                        erlang:element(3, Dep),
                        Project_root
                    ),
                    {dependency, erlang:element(2, Dep), Resolved};

                false ->
                    Dep
            end
        end
    ).

-file("src/glipt/runner.gleam", 139).
-spec maybe_inherit_host_deps(glipt@parser:script_meta(), binary()) -> glipt@parser:script_meta().
maybe_inherit_host_deps(Meta, Script_dir) ->
    Has_directives = ((erlang:element(2, Meta) /= {error, nil}) orelse not gleam@list:is_empty(
        erlang:element(4, Meta)
    ))
    orelse not gleam@list:is_empty(erlang:element(3, Meta)),
    case Has_directives of
        true ->
            Meta;

        false ->
            case glipt@internal@project:find_project_root(Script_dir) of
                {error, nil} ->
                    Meta;

                {ok, Root} ->
                    case simplifile:read(<<Root/binary, "/gleam.toml"/utf8>>) of
                        {error, _} ->
                            Meta;

                        {ok, Content} ->
                            Deps = glipt@internal@toml:parse_deps(Content),
                            Resolved_deps = resolve_relative_paths(Deps, Root),
                            Gleam_constraint = glipt@internal@toml:parse_gleam_version(
                                Content
                            ),
                            {script_meta, Gleam_constraint, [], Resolved_deps}
                    end
            end
    end.

-file("src/glipt/runner.gleam", 28).
-spec run(run_options()) -> {ok, binary()} | {error, run_error()}.
run(Opts) ->
    gleam@result:'try'(
        begin
            _pipe = simplifile:read(erlang:element(2, Opts)),
            gleam@result:map_error(
                _pipe,
                fun(Field@0) -> {file_error, Field@0} end
            )
        end,
        fun(Source) ->
            Parsed = glipt@parser:parse(Source),
            Script_dir = glipt@internal@path:dirname(erlang:element(2, Opts)),
            Meta = maybe_inherit_host_deps(Parsed, Script_dir),
            Key = glipt@internal@cache:cache_key(Source, Meta),
            Module_name = glipt@internal@path:drop_extension(
                glipt@internal@path:basename(erlang:element(2, Opts))
            ),
            Entry_module = case erlang:element(4, Opts) of
                <<"main"/utf8>> ->
                    Module_name;

                _ ->
                    <<"glipt_entry"/utf8>>
            end,
            case glipt@internal@cache:is_cached(Key) of
                true ->
                    execute(
                        Key,
                        Entry_module,
                        erlang:element(3, Opts),
                        erlang:element(5, Opts)
                    );

                false ->
                    gleam@result:'try'(
                        setup_project(
                            Key,
                            erlang:element(2, Opts),
                            Source,
                            Meta,
                            erlang:element(3, Opts),
                            erlang:element(4, Opts),
                            Module_name
                        ),
                        fun(_) ->
                            execute(
                                Key,
                                Entry_module,
                                erlang:element(3, Opts),
                                erlang:element(5, Opts)
                            )
                        end
                    )
            end
        end
    ).