Skip to content

Commit

Permalink
include stub when genereating using grpc.* plugins closes #3
Browse files Browse the repository at this point in the history
  • Loading branch information
drowzy committed May 21, 2024
1 parent f3bce60 commit e7af362
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 57 deletions.
4 changes: 2 additions & 2 deletions lib/mix/protobuf.generate.ex
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ defmodule Mix.Tasks.Protobuf.Generate do
gen_descriptors?: Keyword.get(opts, :generate_descriptors, false),
plugins: plugins,
transform_module: transform_module,
package_prefix: Keyword.get(opts, :package_prefix)
# include_docs?: Keyword.get(opts, :include_docs, false)
package_prefix: Keyword.get(opts, :package_prefix),
include_docs?: Keyword.get(opts, :include_docs, false)
}

request = decode(files, imports, bin)
Expand Down
10 changes: 10 additions & 0 deletions lib/protobuf_generate/plugins/grpc.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ defmodule ProtobufGenerate.Plugins.GRPC do
def template do
"""
defmodule <%= @module %>.Service do
<%= unless @module_doc? do %>
@moduledoc false
<% end %>
use GRPC.Service, name: <%= inspect(@service_name) %>, protoc_gen_elixir_version: "<%= @version %>"
<%= if @descriptor_fun_body do %>
Expand All @@ -26,6 +28,13 @@ defmodule ProtobufGenerate.Plugins.GRPC do
rpc :<%= method_name %>, <%= input %>, <%= output %>
<% end %>
end
defmodule <%= @module %>.Stub do
<%= unless @module_doc? do %>
@moduledoc false
<% end %>
use GRPC.Stub, service: <%= @module %>.Service
end
"""
end

Expand Down Expand Up @@ -57,6 +66,7 @@ defmodule ProtobufGenerate.Plugins.GRPC do
service_name: name,
methods: methods,
descriptor_fun_body: descriptor_fun_body,
module_doc?: ctx.include_docs?,
version: Util.version()
]}
end
Expand Down
9 changes: 9 additions & 0 deletions lib/protobuf_generate/plugins/grpc_with_options.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ defmodule ProtobufGenerate.Plugins.GRPCWithOptions do
def template do
"""
defmodule <%= @module %>.Service do
<%= unless @module_doc? do %>
@moduledoc false
<% end %>
use GRPC.Service, name: <%= inspect(@service_name) %>, protoc_gen_elixir_version: "<%= @version %>"
<%= if @descriptor_fun_body do %>
Expand All @@ -27,6 +29,13 @@ defmodule ProtobufGenerate.Plugins.GRPCWithOptions do
rpc :<%= method_name %>, <%= input %>, <%= output %>, <%= options %>
<% end %>
end
defmodule <%= @module %>.Stub do
<%= unless @module_doc? do %>
@moduledoc false
<% end %>
use GRPC.Stub, service: <%= @module %>.Service
end
"""
end

Expand Down
10 changes: 8 additions & 2 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,21 @@ defmodule ProtobufGenerate.MixProject do
# Run "mix help deps" to learn about dependencies.
defp deps do
[
{:protobuf, "~> 0.11"},
{:protobuf, "~> 0.12"},
{:ex_doc, ">= 0.0.0", only: :dev, runtime: false},
{:google_protobuf,
github: "protocolbuffers/protobuf",
branch: "main",
submodules: true,
app: false,
compile: false,
only: [:dev, :test]}
only: [:dev, :test]},
{:googleapis,
github: "googleapis/googleapis",
branch: "master",
app: false,
compile: false,
only: [:dev, :test]},
]
end
end
3 changes: 2 additions & 1 deletion mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
"earmark_parser": {:hex, :earmark_parser, "1.4.29", "149d50dcb3a93d9f3d6f3ecf18c918fb5a2d3c001b5d3305c926cddfbd33355b", [:mix], [], "hexpm", "4902af1b3eb139016aed210888748db8070b8125c2342ce3dcae4f38dcc63503"},
"ex_doc": {:hex, :ex_doc, "0.29.0", "4a1cb903ce746aceef9c1f9ae8a6c12b742a5461e6959b9d3b24d813ffbea146", [:mix], [{:earmark_parser, "~> 1.4.19", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "f096adb8bbca677d35d278223361c7792d496b3fc0d0224c9d4bc2f651af5db1"},
"google_protobuf": {:git, "https://github.com/protocolbuffers/protobuf.git", "c7647cb04ad67eabe6abe2c2d0c6cdb29b646966", [branch: "main", submodules: true]},
"googleapis": {:git, "https://github.com/googleapis/googleapis.git", "dac915afe45497685f0409e9f5114808b5de9a64", [branch: "master"]},
"makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"},
"makeup_elixir": {:hex, :makeup_elixir, "0.16.0", "f8c570a0d33f8039513fbccaf7108c5d750f47d8defd44088371191b76492b0b", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "28b2cbdc13960a46ae9a8858c4bebdec3c9a6d7b4b9e7f4ed1502f8159f338e7"},
"makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"},
"nimble_parsec": {:hex, :nimble_parsec, "1.2.3", "244836e6e3f1200c7f30cb56733fd808744eca61fd182f731eac4af635cc6d0b", [:mix], [], "hexpm", "c8d789e39b9131acf7b99291e93dae60ab48ef14a7ee9d58c6964f59efb570b0"},
"protobuf": {:hex, :protobuf, "0.11.0", "58d5531abadea3f71135e97bd214da53b21adcdb5b1420aee63f4be8173ec927", [:mix], [{:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "30ad9a867a5c5a0616cac9765c4d2c2b7b0030fa81ea6d0c14c2eb5affb6ac52"},
"protobuf": {:hex, :protobuf, "0.12.0", "58c0dfea5f929b96b5aa54ec02b7130688f09d2de5ddc521d696eec2a015b223", [:mix], [{:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "75fa6cbf262062073dd51be44dd0ab940500e18386a6c4e87d5819a58964dc45"},
}
132 changes: 81 additions & 51 deletions test/mix/tasks/protobuf.generate_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ defmodule Mix.Tasks.Protobuf.GenerateTest do
# https://github.com/elixir-protobuf/protobuf/blob/main/test/protobuf/protoc/cli_integration_test.exs
#
import Mix.Tasks.Protobuf.Generate, only: [run: 1]
import ProtobufGenerate.TestHelpers, only: [tmp_dir: 1, fetch_docs_from_bytecode: 1]
import ProtobufGenerate.TestHelpers, only: [tmp_dir: 1]

setup :tmp_dir

Expand Down Expand Up @@ -65,36 +65,6 @@ defmodule Mix.Tasks.Protobuf.GenerateTest do
assert descriptor.name == "User"
end

# Available after Protobuf 0.11+
@tag :skip
test "include_docs option", %{tmp_dir: tmp_dir, proto_path: proto_path} do
run([
"--include-path=#{tmp_dir}",
"--output-path=#{tmp_dir}",
"--include-docs=true",
proto_path
])

modules_and_docs = get_docs_and_clean_modules_on_exit("#{tmp_dir}/user.pb.ex")

assert [{Foo.User, docs}] = modules_and_docs
assert {:docs_v1, _, :elixir, _, module_doc, _, _} = docs
assert module_doc != :hidden
end

test "hides docs when include_docs is not true", %{tmp_dir: tmp_dir, proto_path: proto_path} do
run([
"--include-path=#{tmp_dir}",
"--output-path=#{tmp_dir}",
proto_path
])

modules_and_docs = get_docs_and_clean_modules_on_exit("#{tmp_dir}/user.pb.ex")

assert [{Foo.User, docs}] = modules_and_docs
assert {:docs_v1, _, :elixir, _, :hidden, _, _} = docs
end

test "package_prefix mypkg", %{tmp_dir: tmp_dir, proto_path: proto_path} do
run([
"--include-path=#{tmp_dir}",
Expand Down Expand Up @@ -201,13 +171,91 @@ defmodule Mix.Tasks.Protobuf.GenerateTest do
proto_path
])

assert [_, _, _, service] =
assert [_, _, _, service, stub] =
compile_file_and_clean_modules_on_exit("#{tmp_dir}/helloworld.pb.ex")

assert service == Helloworld.Greeter.Service
assert stub == Helloworld.Greeter.Stub
assert [{:SayHello, _, _, _}, {:SayHelloFrom, _, _, _}] = service.__rpc_calls__()
end

@tag :skip
test "with grpc options plugin", %{tmp_dir: tmp_dir} do
# proto_path = Path.join(tmp_dir, "helloworld_options.proto")
proto_path = Path.join(tmp_dir, "helloworld_options.proto")
paths = ["google/api/annotations.proto", "google/api/http.proto", "helloworld_options.proto"]

File.write!(proto_path, """
syntax = "proto3";
import "google/api/annotations.proto";
import "google/protobuf/timestamp.proto";
package helloworld;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {
option (google.api.http) = {
get: "/v1/greeter/{name}"
};
}
rpc SayHelloFrom (HelloRequestFrom) returns (HelloReply) {
option (google.api.http) = {
post: "/v1/greeter"
body: "*"
};
}
}
message HelloRequest {
string name = 1;
}
message HelloRequestFrom {
string name = 1;
string from = 2;
}
message HelloReply {
string message = 1;
google.protobuf.Timestamp today = 2;
}
""")

run (
[
"--include-path=#{tmp_dir}",
"--output-path=#{tmp_dir}",
"--include-path=#{Mix.Project.deps_paths().googleapis}",
"google/api/annotations.proto",
"google/api/http.proto"
]
)
_ = compile_file_and_clean_modules_on_exit("#{tmp_dir}/google/api/annotations.pb.ex")
_ = compile_file_and_clean_modules_on_exit("#{tmp_dir}/google/api/http.pb.ex")
# "--include-path=#{Mix.Project.deps_paths().google_protobuf}/src",
run(
[
"--include-path=#{tmp_dir}",
"--include-path=#{Mix.Project.deps_paths().googleapis}",
"--output-path=#{tmp_dir}",
"--plugin=ProtobufGenerate.Plugins.GRPCWithOptions"
] ++ paths
)

Code.ensure_loaded?(GRPC)

assert [_, _, _, service, stub] =
compile_file_and_clean_modules_on_exit("#{tmp_dir}/helloworld_options.pb.ex")

assert service == Helloworld.Greeter.Service
assert stub == Helloworld.Greeter.Stub
assert [{:SayHello, _, _, opts1}, {:SayHelloFrom, _, _, opts2}] = service.__rpc_calls__()
assert opts1 == %{}
assert opts2 == %{}
end


defp compile_file_and_clean_modules_on_exit(path) do
modules =
path
Expand All @@ -216,29 +264,11 @@ defmodule Mix.Tasks.Protobuf.GenerateTest do

on_exit(fn ->
Enum.each(modules, fn mod ->
:code.delete(mod)
:code.purge(mod)
end)
end)

modules
end

defp get_docs_and_clean_modules_on_exit(path) do
modules_and_docs =
path
|> Code.compile_file()
|> Enum.map(fn {mod, bytecode} ->
{mod, fetch_docs_from_bytecode(bytecode)}
end)

on_exit(fn ->
Enum.each(modules_and_docs, fn {mod, _bytecode} ->
:code.delete(mod)
:code.purge(mod)
end)
end)

modules_and_docs
modules
end
end
2 changes: 1 addition & 1 deletion test/test_helper.exs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ defmodule ProtobufGenerate.TestHelpers do

# This code is taken from Code.fetch_docs/1 in Elixir (v1.13 in particular).
def fetch_docs_from_bytecode(bytecode) when is_binary(bytecode) do
docs_chunk = 'Docs'
docs_chunk = ~c"Docs"
assert {:ok, {_module, [{^docs_chunk, bin}]}} = :beam_lib.chunks(bytecode, [docs_chunk])
:erlang.binary_to_term(bin)
end
Expand Down

0 comments on commit e7af362

Please sign in to comment.