Packages

CLI tool for the Protozoa Protocol Buffers library

Current section

Files

Jump to
protozoa_dev src protozoa@dev.erl
Raw

src/protozoa@dev.erl

-module(protozoa@dev).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/protozoa/dev.gleam").
-export([main/0]).
-export_type([command/0, change_result/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" Protozoa Dev - Protocol Buffer Compiler CLI for Gleam\n"
"\n"
" CLI tool for generating Gleam code from Protocol Buffer (.proto) files with complete proto3 support.\n"
).
-type command() :: generate | check.
-type change_result() :: unchanged | {changed, list(binary())}.
-file("src/protozoa/dev.gleam", 100).
-spec extract_imports(list(binary()), list(binary())) -> {list(binary()),
list(binary())}.
extract_imports(Args, Acc) ->
case Args of
[Arg | Rest] ->
case gleam_stdlib:string_starts_with(Arg, <<"-I"/utf8>>) of
true ->
Path = gleam@string:drop_start(Arg, 2),
extract_imports(Rest, [Path | Acc]);
false ->
{lists:reverse(Acc), Args}
end;
[] ->
{lists:reverse(Acc), []}
end.
-file("src/protozoa/dev.gleam", 89).
-spec parse_manual_mode(list(binary())) -> {ok,
{command(), binary(), binary(), list(binary())}} |
{error, snag:snag()}.
parse_manual_mode(Args) ->
{Imports, Remaining} = extract_imports(Args, []),
case Remaining of
[Input, Output] ->
{ok, {generate, Input, Output, Imports}};
[Input@1] ->
{ok, {generate, Input@1, <<"."/utf8>>, Imports}};
_ ->
snag:error(<<"Invalid arguments"/utf8>>)
end.
-file("src/protozoa/dev.gleam", 118).
-spec discover_project_structure() -> {ok, {binary(), binary()}} |
{error, snag:snag()}.
discover_project_structure() ->
gleam@result:'try'(
begin
_pipe = protozoa@internal@project:name(),
gleam@result:map_error(
_pipe,
fun(_) ->
snag:new(<<"Project name not found in gleam.toml"/utf8>>)
end
)
end,
fun(Name) ->
Proto_dir = filepath:join(
protozoa@internal@project:src(),
<<Name/binary, "/proto"/utf8>>
),
gleam@result:'try'(
begin
_pipe@1 = simplifile_erl:read_directory(Proto_dir),
snag:map_error(_pipe@1, fun simplifile:describe_error/1)
end,
fun(Proto_files) ->
Proto_file = <<<<<<Proto_dir/binary, "/"/utf8>>/binary,
Name/binary>>/binary,
".proto"/utf8>>,
case gleam@list:any(
Proto_files,
fun(F) ->
gleam_stdlib:string_ends_with(F, <<".proto"/utf8>>)
end
) of
true ->
{ok, {Proto_file, Proto_dir}};
false ->
snag:error(<<"No proto files found"/utf8>>)
end
end
)
end
).
-file("src/protozoa/dev.gleam", 62).
-spec parse_auto_mode(list(binary())) -> {ok,
{command(), binary(), binary(), list(binary())}} |
{error, snag:snag()}.
parse_auto_mode(Args) ->
Cmd = case Args of
[<<"check"/utf8>>] ->
check;
_ ->
generate
end,
case discover_project_structure() of
{ok, {Input, Output}} ->
{ok, {Cmd, Input, Output, [<<"."/utf8>>]}};
{error, Error} ->
case Cmd of
check ->
{ok, {Cmd, <<"."/utf8>>, <<"."/utf8>>, [<<"."/utf8>>]}};
generate ->
_pipe = {error, Error},
snag:context(
_pipe,
<<"No gleam.toml found or no proto files detected"/utf8>>
)
end
end.
-file("src/protozoa/dev.gleam", 52).
-spec parse_args(list(binary())) -> {ok,
{command(), binary(), binary(), list(binary())}} |
{error, snag:snag()}.
parse_args(Args) ->
case Args of
[] ->
parse_auto_mode(Args);
[<<"check"/utf8>>] ->
parse_auto_mode(Args);
[<<"-h"/utf8>>] ->
snag:error(<<"help"/utf8>>);
[<<"--help"/utf8>>] ->
snag:error(<<"help"/utf8>>);
_ ->
parse_manual_mode(Args)
end.
-file("src/protozoa/dev.gleam", 226).
-spec resolve_all_imports(binary(), list(binary())) -> {ok,
{protozoa@parser:proto_file(),
protozoa@internal@import_resolver:import_resolver()}} |
{error, snag:snag()}.
resolve_all_imports(Input, Import_paths) ->
Resolver = begin
_pipe = protozoa@internal@import_resolver:new(),
protozoa@internal@import_resolver:with_search_paths(
_pipe,
[<<"."/utf8>> | Import_paths]
)
end,
_pipe@1 = protozoa@internal@import_resolver:resolve_imports(Resolver, Input),
gleam@result:map_error(
_pipe@1,
fun(Err) ->
snag:new(
<<"Import resolution failed: "/utf8,
(protozoa@internal@import_resolver:describe_error(Err))/binary>>
)
end
).
-file("src/protozoa/dev.gleam", 183).
-spec generate_files(binary(), binary(), list(binary())) -> {ok, list(binary())} |
{error, snag:snag()}.
generate_files(Input, Output, Import_paths) ->
_ = simplifile:create_directory_all(Output),
gleam@result:'try'(
resolve_all_imports(Input, Import_paths),
fun(_use0) ->
{_, Resolver} = _use0,
Files = protozoa@internal@import_resolver:get_all_loaded_files(
Resolver
),
Registry = protozoa@internal@import_resolver:get_type_registry(
Resolver
),
Paths = gleam@list:map(
Files,
fun(Entry) ->
{Path, Content} = Entry,
{path, Path, Content}
end
),
gleam@result:'try'(
begin
_pipe = protozoa@internal@codegen:generate_combined_proto_file(
Paths,
Registry,
Output
),
gleam@result:map_error(
_pipe,
fun(Err) ->
snag:new(<<"Codegen failed: "/utf8, Err/binary>>)
end
)
end,
fun(Generated) ->
{ok,
gleam@list:map(
Generated,
fun(Entry@1) -> erlang:element(1, Entry@1) end
)}
end
)
end
).
-file("src/protozoa/dev.gleam", 208).
-spec check_changes(binary(), binary(), list(binary())) -> {ok, change_result()} |
{error, snag:snag()}.
check_changes(Input, Output, Import_paths) ->
case generate_files(Input, Output, Import_paths) of
{ok, _} ->
{ok, unchanged};
{error, _} ->
{ok, unchanged}
end.
-file("src/protozoa/dev.gleam", 242).
-spec print_usage() -> nil.
print_usage() ->
gleam_stdlib:println(
<<"Protozoa Dev - Protocol Buffer Compiler CLI for Gleam"/utf8>>
),
gleam_stdlib:println(<<""/utf8>>),
gleam_stdlib:println(<<"Recommended Usage:"/utf8>>),
gleam_stdlib:println(
<<" gleam run -m protozoa_dev # Auto-detect and generate"/utf8>>
),
gleam_stdlib:println(
<<" gleam run -m protozoa_dev check # Check for changes"/utf8>>
),
gleam_stdlib:println(<<""/utf8>>),
gleam_stdlib:println(<<"Advanced Usage:"/utf8>>),
gleam_stdlib:println(
<<" gleam run -m protozoa_dev input.proto [dir] # Manual mode"/utf8>>
),
gleam_stdlib:println(
<<" gleam run -m protozoa_dev -Ipath input.proto # With import paths"/utf8>>
),
gleam_stdlib:println(<<""/utf8>>),
gleam_stdlib:println(<<"Options:"/utf8>>),
gleam_stdlib:println(
<<" -I<path> # Add import search path"/utf8>>
),
gleam_stdlib:println(
<<" --help # Show help"/utf8>>
).
-file("src/protozoa/dev.gleam", 139).
-spec run_generate(binary(), binary(), list(binary())) -> nil.
run_generate(Input, Output, Import_paths) ->
gleam_stdlib:println(<<"🔄 Generating proto files..."/utf8>>),
case generate_files(Input, Output, Import_paths) of
{ok, Files} ->
gleam_stdlib:println(
<<<<"✅ Successfully generated "/utf8,
(erlang:integer_to_binary(erlang:length(Files)))/binary>>/binary,
" file(s):"/utf8>>
),
gleam@list:each(
Files,
fun(F) -> gleam_stdlib:println(<<" - "/utf8, F/binary>>) end
),
case shellout:command(
<<"gleam"/utf8>>,
[<<"format"/utf8>>],
<<"."/utf8>>,
[]
) of
{ok, _} ->
nil;
{error, {_, String}} ->
gleam_stdlib:println_error(
<<"❌ Failed to format files: "/utf8, String/binary>>
)
end;
{error, Err} ->
gleam_stdlib:println_error(
<<"❌ Generation failed: "/utf8,
(snag:pretty_print(Err))/binary>>
),
erlang:halt(1)
end.
-file("src/protozoa/dev.gleam", 166).
-spec run_check(binary(), binary(), list(binary())) -> nil.
run_check(Input, Output, Import_paths) ->
gleam_stdlib:println(<<"🔍 Checking proto file changes..."/utf8>>),
case check_changes(Input, Output, Import_paths) of
{ok, unchanged} ->
gleam_stdlib:println(<<"✅ Files are up to date"/utf8>>);
{ok, {changed, Changes}} ->
gleam_stdlib:println(<<"⚠️ Changes detected:"/utf8>>),
gleam@list:each(
Changes,
fun(C) -> gleam_stdlib:println(<<" - "/utf8, C/binary>>) end
),
gleam_stdlib:println(<<"💡 Run without 'check' to regenerate"/utf8>>),
erlang:halt(1);
{error, Err} ->
gleam_stdlib:println_error(
<<"❌ Check failed: "/utf8, (snag:pretty_print(Err))/binary>>
),
erlang:halt(1)
end.
-file("src/protozoa/dev.gleam", 31).
?DOC(" Main CLI entry point\n").
-spec main() -> nil.
main() ->
Args = erlang:element(4, argv:load()),
case parse_args(Args) of
{ok, {Cmd, Input, Output, Imports}} ->
case Cmd of
generate ->
run_generate(Input, Output, Imports);
check ->
run_check(Input, Output, Imports)
end;
{error, {snag, <<"help"/utf8>>, _}} ->
print_usage(),
erlang:halt(0);
{error, Error} ->
gleam_stdlib:println_error(
<<"❌ Error: "/utf8,
(begin
_pipe = Error,
snag:pretty_print(_pipe)
end)/binary>>
),
print_usage(),
erlang:halt(1)
end.