Current section

Files

Jump to
open_feature_provider_flagd lib mix tasks proto.gen.ex
Raw

lib/mix/tasks/proto.gen.ex

defmodule Mix.Tasks.Proto.Gen do
@moduledoc """
Mix task for downloading and compiling flagd protobuf definitions.
This task:
1. Downloads the `evaluation.proto` and `sync.proto` files from the official
flagd Buf registry.
2. Saves them to `priv/protos/`.
3. Runs `protoc` to generate Elixir + gRPC modules into
`lib/openfeature/provider/flagd/proto/`.
## Usage
Run the following from the root of the project:
mix proto.gen
This is primarily intended for development workflows until `buf` supports Elixir
as a target. Generated modules are checked in and used by the Flagd provider.
"""
use Mix.Task
@shortdoc "Downloads flagd protos and generates Elixir modules"
@impl true
def run(_args) do
Application.ensure_all_started(:req)
Mix.shell().info("Downloading protos...")
Enum.each(buf_urls(), &download_proto!/1)
Mix.shell().info("Generating Elixir modules with protoc...")
protos =
Path.wildcard("priv/protos/**/*.proto")
|> Enum.join(" ")
cmd =
"protoc --proto_path=priv/protos " <>
"--elixir_out=plugins=grpc:./lib/openfeature/provider/flagd/proto " <>
protos
Mix.shell().info("Running: #{cmd}")
Mix.shell().cmd(cmd)
Mix.shell().info("Formatting generated code...")
Mix.Task.run("format")
end
defp download_proto!({url, path}) do
File.mkdir_p!(Path.dirname(path))
Mix.shell().info("Fetching: #{url}")
case Req.get(url) do
{:ok, %Req.Response{status: 200, body: body}} ->
File.write!(path, body)
Mix.shell().info("✅ Wrote: #{path}")
{:ok, %Req.Response{status: status}} ->
Mix.raise("❌ Failed to fetch #{url} (status: #{status})")
{:error, error} ->
Mix.raise("❌ Req error fetching #{url}: #{inspect(error)}")
end
end
defp buf_urls do
[
{"https://buf.build/open-feature/flagd/raw/main/-/flagd/evaluation/v1/evaluation.proto",
"priv/protos/evaluation/v1/evaluation.proto"},
{"https://buf.build/open-feature/flagd/raw/main/-/flagd/sync/v1/sync.proto", "priv/protos/sync/v1/sync.proto"}
]
end
end