From c8e0a523c12aa0ffe90905e040146e41f03a3aff Mon Sep 17 00:00:00 2001 From: Lizzie Paquette <33362730+lizziepaquette@users.noreply.github.com> Date: Wed, 8 Apr 2020 12:17:18 -0700 Subject: [PATCH 1/7] Add compiler option to swap out using module (#1) * usurp using macro * address missed message types and fix Elixir.Protobuf problem * fix spacing --- lib/protobuf/protoc/cli.ex | 5 +++++ lib/protobuf/protoc/context.ex | 5 ++++- lib/protobuf/protoc/generator/enum.ex | 9 ++++++++- lib/protobuf/protoc/generator/extension.ex | 2 +- lib/protobuf/protoc/generator/message.ex | 6 ++++-- lib/protobuf/protoc/template.ex | 22 +++++++++++++++++++--- priv/templates/enum.ex.eex | 4 ++-- priv/templates/extension.ex.eex | 2 +- priv/templates/message.ex.eex | 2 +- 9 files changed, 45 insertions(+), 12 deletions(-) diff --git a/lib/protobuf/protoc/cli.ex b/lib/protobuf/protoc/cli.ex index 58a15047..f4a9d3aa 100644 --- a/lib/protobuf/protoc/cli.ex +++ b/lib/protobuf/protoc/cli.ex @@ -66,6 +66,11 @@ defmodule Protobuf.Protoc.CLI do parse_params(ctx, t) end + def parse_params(ctx, ["using_module=" <> using_module | t]) do + ctx = %{ctx | using_module: using_module} + parse_params(ctx, t) + end + def parse_params(ctx, _), do: ctx @doc false diff --git a/lib/protobuf/protoc/context.ex b/lib/protobuf/protoc/context.ex index 9c7dacbf..ce0e4fb2 100644 --- a/lib/protobuf/protoc/context.ex +++ b/lib/protobuf/protoc/context.ex @@ -29,7 +29,10 @@ defmodule Protobuf.Protoc.Context do gen_descriptors?: false, # Elixirpb.FileOptions - custom_file_options: %{} + custom_file_options: %{}, + + # Allow custom code injection + using_module: "Protobuf" def cal_file_options(ctx, nil) do %{ctx | custom_file_options: %{}, module_prefix: ctx.package || ""} diff --git a/lib/protobuf/protoc/generator/enum.ex b/lib/protobuf/protoc/generator/enum.ex index 9c3dd4b6..d258d5f5 100644 --- a/lib/protobuf/protoc/generator/enum.ex +++ b/lib/protobuf/protoc/generator/enum.ex @@ -13,7 +13,14 @@ defmodule Protobuf.Protoc.Generator.Enum do generate_desc = if ctx.gen_descriptors?, do: desc, else: nil type = generate_type(desc.value) - Protobuf.Protoc.Template.enum(msg_name, msg_opts(ctx, desc), fields, type, generate_desc) + Protobuf.Protoc.Template.enum( + msg_name, + msg_opts(ctx, desc), + fields, + type, + generate_desc, + ctx.using_module + ) end def generate_type(fields) do diff --git a/lib/protobuf/protoc/generator/extension.ex b/lib/protobuf/protoc/generator/extension.ex index 8ce1d2b7..e5f19d99 100644 --- a/lib/protobuf/protoc/generator/extension.ex +++ b/lib/protobuf/protoc/generator/extension.ex @@ -24,7 +24,7 @@ defmodule Protobuf.Protoc.Generator.Extension do else name = Util.trans_name(@ext_postfix) msg_name = Util.mod_name(ctx, ns ++ [name]) - Protobuf.Protoc.Template.extension(msg_name, msg_opts(ctx, desc), extends) + Protobuf.Protoc.Template.extension(msg_name, msg_opts(ctx, desc), extends, ctx.using_module) end end diff --git a/lib/protobuf/protoc/generator/message.ex b/lib/protobuf/protoc/generator/message.ex index 33d631a5..d1c399bc 100644 --- a/lib/protobuf/protoc/generator/message.ex +++ b/lib/protobuf/protoc/generator/message.ex @@ -34,7 +34,8 @@ defmodule Protobuf.Protoc.Generator.Message do fields: fields, oneofs: oneofs_str(desc.oneof_decl), desc: generate_desc, - extensions: extensions + extensions: extensions, + using_module: ctx.using_module } end @@ -47,7 +48,8 @@ defmodule Protobuf.Protoc.Generator.Message do msg_struct[:oneofs], gen_fields(syntax, msg_struct[:fields]), msg_struct[:desc], - gen_extensions(msg_struct[:extensions]) + gen_extensions(msg_struct[:extensions]), + msg_struct[:using_module] ) end diff --git a/lib/protobuf/protoc/template.ex b/lib/protobuf/protoc/template.ex index 2a07c454..bdbcba9f 100644 --- a/lib/protobuf/protoc/template.ex +++ b/lib/protobuf/protoc/template.ex @@ -11,11 +11,25 @@ defmodule Protobuf.Protoc.Template do :def, :message, @msg_tmpl, - [:name, :options, :struct_fields, :typespec, :oneofs, :fields, :desc, :extensions], + [ + :name, + :options, + :struct_fields, + :typespec, + :oneofs, + :fields, + :desc, + :extensions, + :using_module + ], trim: true ) - EEx.function_from_file(:def, :enum, @enum_tmpl, [:name, :options, :fields, :type, :desc], + EEx.function_from_file( + :def, + :enum, + @enum_tmpl, + [:name, :options, :fields, :type, :desc, :using_module], trim: true ) @@ -23,5 +37,7 @@ defmodule Protobuf.Protoc.Template do trim: true ) - EEx.function_from_file(:def, :extension, @ext_tmpl, [:name, :options, :extends], trim: true) + EEx.function_from_file(:def, :extension, @ext_tmpl, [:name, :options, :extends, :using_module], + trim: true + ) end diff --git a/priv/templates/enum.ex.eex b/priv/templates/enum.ex.eex index 690695ad..d38080f0 100644 --- a/priv/templates/enum.ex.eex +++ b/priv/templates/enum.ex.eex @@ -1,7 +1,7 @@ defmodule <%= name %> do @moduledoc false - use Protobuf<%= options %> - + use <%= using_module %><%= options %> + <%= type %> <%= if not is_nil(desc) do %> diff --git a/priv/templates/extension.ex.eex b/priv/templates/extension.ex.eex index 3c29c173..da77f9bf 100644 --- a/priv/templates/extension.ex.eex +++ b/priv/templates/extension.ex.eex @@ -1,6 +1,6 @@ defmodule <%= name %> do @moduledoc false - use Protobuf<%= options %> + use <%= using_module %><%= options %> <%= for ext <- extends do %> extend <%= ext %> <% end %> diff --git a/priv/templates/message.ex.eex b/priv/templates/message.ex.eex index 9f0aa76f..9e5c970d 100644 --- a/priv/templates/message.ex.eex +++ b/priv/templates/message.ex.eex @@ -1,6 +1,6 @@ defmodule <%= name %> do @moduledoc false - use Protobuf<%= options %> + use <%= using_module %><%= options %> <%= typespec %> defstruct [<%= struct_fields %>] From c12e546e4dbb148448cc98b17ec7b927689e7a31 Mon Sep 17 00:00:00 2001 From: Lizzie Paquette Date: Wed, 8 Apr 2020 12:20:27 -0700 Subject: [PATCH 2/7] add extype field extension --- lib/brex_elixirpb.pb.ex | 20 ++++++++++++++++++++ src/brex_elixirpb.proto | 22 ++++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 lib/brex_elixirpb.pb.ex create mode 100644 src/brex_elixirpb.proto diff --git a/lib/brex_elixirpb.pb.ex b/lib/brex_elixirpb.pb.ex new file mode 100644 index 00000000..7124410e --- /dev/null +++ b/lib/brex_elixirpb.pb.ex @@ -0,0 +1,20 @@ +defmodule Brex.Elixirpb.FieldOptions do + @moduledoc false + use Protobuf, syntax: :proto2 + + @type t :: %__MODULE__{ + extype: String.t() + } + defstruct [:extype] + + field :extype, 1, optional: true, type: :string +end + +defmodule Brex.Elixirpb.PbExtension do + @moduledoc false + use Protobuf, syntax: :proto2 + + extend Google.Protobuf.FieldOptions, :field, 65007, + optional: true, + type: Brex.Elixirpb.FieldOptions +end diff --git a/src/brex_elixirpb.proto b/src/brex_elixirpb.proto new file mode 100644 index 00000000..233c5f6a --- /dev/null +++ b/src/brex_elixirpb.proto @@ -0,0 +1,22 @@ +syntax = "proto2"; + +package brex.elixirpb; +import "google/protobuf/descriptor.proto"; + +// Defines an extension to specify the elixir type generated for the given field. + +// For example, +// google.protobuf.StringValue my_string = 1 [(brex.elixirpb.field).extype="String.t"]; + +// To compile +//protoc --plugin=/Users/lizard/Projects/Work/git/brex/protobuf-elixir/protoc-gen-elixir --proto_path=lib --elixir_out=lib brex_elixirpb.proto + +message FieldOptions { + // Specify an elixir type to generate for this field. This will override usual type. + optional string extype = 1; +} + +extend google.protobuf.FieldOptions { + // Note: number to change + optional FieldOptions field = 65007; +} \ No newline at end of file From a326bf5033ef443ff15fd17ab4c2506e18a318fc Mon Sep 17 00:00:00 2001 From: Lizzie Paquette Date: Mon, 6 Apr 2020 15:20:57 -0700 Subject: [PATCH 3/7] wip that works, committing in case I f it up --- config/config.exs | 3 ++ lib/elixir.pb.ex | 20 +++++++++++++ lib/protobuf/extension/props.ex | 2 +- lib/protobuf/field_props.ex | 6 ++-- lib/protobuf/message_props.ex | 2 +- lib/protobuf/protoc/generator/message.ex | 8 +++++ src/elixir.proto | 24 +++++++++++++++ src/elixirpb.proto | 1 + test/protobuf/dsl_test.exs | 5 ++++ .../protoc/generator/message_test.exs | 30 ++++++++++++++++++- test/support/test_msg.ex | 12 ++++++++ 11 files changed, 108 insertions(+), 5 deletions(-) create mode 100644 lib/elixir.pb.ex create mode 100644 src/elixir.proto diff --git a/config/config.exs b/config/config.exs index d2d855e6..819f061a 100644 --- a/config/config.exs +++ b/config/config.exs @@ -1 +1,4 @@ use Mix.Config + +config :protobuf, extensions: :enabled + diff --git a/lib/elixir.pb.ex b/lib/elixir.pb.ex new file mode 100644 index 00000000..8eb1be76 --- /dev/null +++ b/lib/elixir.pb.ex @@ -0,0 +1,20 @@ +defmodule Brex.Elixir.FieldOptions do + @moduledoc false + use Protobuf, syntax: :proto2 + + @type t :: %__MODULE__{ + extype: String.t() + } + defstruct [:extype] + + field :extype, 1, optional: true, type: :string +end + +defmodule Brex.Elixir.PbExtension do + @moduledoc false + use Protobuf, syntax: :proto2 + + extend Google.Protobuf.FieldOptions, :field, 65_007, + optional: true, + type: Brex.Elixir.FieldOptions +end diff --git a/lib/protobuf/extension/props.ex b/lib/protobuf/extension/props.ex index efef629b..60186943 100644 --- a/lib/protobuf/extension/props.ex +++ b/lib/protobuf/extension/props.ex @@ -5,7 +5,7 @@ defmodule Protobuf.Extension.Props do @moduledoc false @type t :: %__MODULE__{ extendee: module, - field_props: FieldProps.T + field_props: FieldProps.t } defstruct extendee: nil, field_props: nil diff --git a/lib/protobuf/field_props.ex b/lib/protobuf/field_props.ex index 693bed75..88581f22 100644 --- a/lib/protobuf/field_props.ex +++ b/lib/protobuf/field_props.ex @@ -17,7 +17,8 @@ defmodule Protobuf.FieldProps do packed?: boolean, map?: boolean, deprecated?: boolean, - encoded_fnum: iodata + encoded_fnum: iodata, + options: List.t() | nil } defstruct fnum: nil, name: nil, @@ -34,5 +35,6 @@ defmodule Protobuf.FieldProps do packed?: nil, map?: false, deprecated?: false, - encoded_fnum: nil + encoded_fnum: nil, + options: nil end diff --git a/lib/protobuf/message_props.ex b/lib/protobuf/message_props.ex index 5afbbe9d..d8b001b1 100644 --- a/lib/protobuf/message_props.ex +++ b/lib/protobuf/message_props.ex @@ -6,7 +6,7 @@ defmodule Protobuf.MessageProps do @type t :: %__MODULE__{ ordered_tags: [integer], tags_map: %{integer => integer}, - field_props: %{integer => FieldProps.T}, + field_props: %{integer => FieldProps.t}, field_tags: %{atom => integer}, repeated_fields: [atom], embedded_fields: [atom], diff --git a/lib/protobuf/protoc/generator/message.ex b/lib/protobuf/protoc/generator/message.ex index d1c399bc..146a335b 100644 --- a/lib/protobuf/protoc/generator/message.ex +++ b/lib/protobuf/protoc/generator/message.ex @@ -12,6 +12,7 @@ defmodule Protobuf.Protoc.Generator.Message do def generate(ctx, desc) do msg_struct = parse_desc(ctx, desc) + IO.inspect(:stderr, msg_struct, label: :message_struct) ctx = %{ctx | namespace: msg_struct[:new_namespace]} {nested_enums, nested_msgs} = Enum.unzip(gen_nested_msgs(ctx, desc)) @@ -179,8 +180,10 @@ defmodule Protobuf.Protoc.Generator.Message do end def get_field(ctx, f, nested_maps, oneofs) do + opts = field_options(f) map = nested_maps[f.type_name] + opts = if map, do: Map.put(opts, :map, true), else: opts opts = @@ -290,8 +293,13 @@ defmodule Protobuf.Protoc.Generator.Message do end defp merge_field_options(opts, f) do + extype_options = Google.Protobuf.FieldOptions.get_extension(f.options, Brex.Elixir.PbExtension, :field) + + IO.inspect(:stderr, {opts, f.options, extype_options}, label: :together) + opts |> Map.put(:packed, f.options.packed) |> Map.put(:deprecated, f.options.deprecated) + |> Map.put(:options, "#{inspect(extype_options)}") end end diff --git a/src/elixir.proto b/src/elixir.proto new file mode 100644 index 00000000..8c5954c4 --- /dev/null +++ b/src/elixir.proto @@ -0,0 +1,24 @@ +syntax = "proto2"; + +// we should call just elixirpb and merge with Tony's +// https://github.com/tony612/protobuf-elixir/blob/e1d4a23baa1f51c2da58db24f58a26dc4d6511b2/src/elixirpb.proto +package brex.elixir; + +import "google/protobuf/descriptor.proto"; + +// Define an extension to specify the elixir type generated for the given field. + +// Field level options +// +// For example, +// google.protobuf.StringValue my_string = 1 [(brex.elixirpb.field).extype="String.t"]; + +message FieldOptions { + // Specify an elixir type to generate for this field. This will override usual type. + optional string extype = 1; +} + +extend google.protobuf.FieldOptions { + // number to change + optional FieldOptions field = 65007; +} \ No newline at end of file diff --git a/src/elixirpb.proto b/src/elixirpb.proto index 9fa51d26..180cc78b 100644 --- a/src/elixirpb.proto +++ b/src/elixirpb.proto @@ -28,3 +28,4 @@ message FileOptions { extend google.protobuf.FileOptions { optional FileOptions file = 1047; } + diff --git a/test/protobuf/dsl_test.exs b/test/protobuf/dsl_test.exs index 12b7e254..8b0e7fbb 100644 --- a/test/protobuf/dsl_test.exs +++ b/test/protobuf/dsl_test.exs @@ -223,4 +223,9 @@ defmodule Protobuf.DSLTest do assert msg_props.field_props[4].oneof == 1 refute msg_props.field_props[5].oneof end + + test "Extension use case" do + msg_props = TestMsg.Ext.UseCase.__message_props__() + assert %Protobuf.FieldProps{options: [extype: "String.t"]} = msg_props.field_props[1] + end end diff --git a/test/protobuf/protoc/generator/message_test.exs b/test/protobuf/protoc/generator/message_test.exs index 605b1780..f86df076 100644 --- a/test/protobuf/protoc/generator/message_test.exs +++ b/test/protobuf/protoc/generator/message_test.exs @@ -173,7 +173,35 @@ defmodule Protobuf.Protoc.Generator.MessageTest do assert msg =~ "field :a, 1, optional: true, type: :int32, deprecated: true\n" end - test "generete/2 supports message type field" do + test "generate/2 supports extensions on field options" do + ctx = %Context{package: ""} + + opts = Google.Protobuf.FieldOptions.new() + custom_opts = Brex.Elixir.FieldOptions.new(extype: "String.t") + + opts = + Google.Protobuf.FieldOptions.put_extension(opts, Brex.Elixir.PbExtension, :field, custom_opts) + + desc = + Google.Protobuf.DescriptorProto.new( + name: "Foo", + field: [ + Google.Protobuf.FieldDescriptorProto.new( + name: "my_string", + number: 1, + type: :TYPE_MESSAGE, + # type_name: ".google.protobuf.StringValue", + label: :LABEL_OPTIONAL, + options: opts + ) + ] + ) + + {[], [msg]} = Generator.generate(ctx, desc) + assert msg =~ "field :my_string, 1, optional: true, type: :message, options: %Brex.Elixir.FieldOptions{extype: \"String.t\"}\n" + end + + test "generate/2 supports message type field" do ctx = %Context{ package: "", dep_type_mapping: %{ diff --git a/test/support/test_msg.ex b/test/support/test_msg.ex index 9d60154d..27d8f515 100644 --- a/test/support/test_msg.ex +++ b/test/support/test_msg.ex @@ -212,4 +212,16 @@ defmodule TestMsg do extend Ext.Foo2, :bar, 1047, optional: true, type: :string extend Ext.Foo1, :"Parent.foo", 1048, optional: true, type: Ext.EnumFoo, enum: true end + + defmodule Ext.UseCase do + @moduledoc false + use Protobuf, syntax: :proto3 + + @type t :: %__MODULE__{ + my_string: Google.Protobuf.StringValue.t() | nil + } + defstruct [:my_string] + + field :my_string, 1, type: Google.Protobuf.StringValue, options: [extype: "String.t"] + end end From f668a2e8e640055d669eecec07ad855ec6a23521 Mon Sep 17 00:00:00 2001 From: Lizzie Paquette Date: Mon, 6 Apr 2020 20:10:52 -0700 Subject: [PATCH 4/7] I thought extension of extension would be cool but it doesn't work ... --- lib/elixir.pb.ex | 16 +-------- lib/elixirpb.pb.ex | 18 ++++++++-- lib/protobuf/extension.ex | 1 + lib/protobuf/protoc/generator/message.ex | 33 +++++++++++++++---- lib/protobuf/protoc/generator/util.ex | 1 + src/elixir.proto | 16 ++++----- src/elixirpb.proto | 11 +++++++ .../protoc/generator/message_test.exs | 11 ++++--- 8 files changed, 70 insertions(+), 37 deletions(-) diff --git a/lib/elixir.pb.ex b/lib/elixir.pb.ex index 8eb1be76..edca4027 100644 --- a/lib/elixir.pb.ex +++ b/lib/elixir.pb.ex @@ -1,20 +1,6 @@ -defmodule Brex.Elixir.FieldOptions do - @moduledoc false - use Protobuf, syntax: :proto2 - - @type t :: %__MODULE__{ - extype: String.t() - } - defstruct [:extype] - - field :extype, 1, optional: true, type: :string -end - defmodule Brex.Elixir.PbExtension do @moduledoc false use Protobuf, syntax: :proto2 - extend Google.Protobuf.FieldOptions, :field, 65_007, - optional: true, - type: Brex.Elixir.FieldOptions + extend Elixirpb.FieldOptions, :extype, 1000, optional: true, type: :string end diff --git a/lib/elixirpb.pb.ex b/lib/elixirpb.pb.ex index 0d64c696..f820cd6a 100644 --- a/lib/elixirpb.pb.ex +++ b/lib/elixirpb.pb.ex @@ -3,11 +3,24 @@ defmodule Elixirpb.FileOptions do use Protobuf, syntax: :proto2 @type t :: %__MODULE__{ - module_prefix: String.t() + module_prefix: String.t(), + __pb_extensions__: map } - defstruct [:module_prefix] + defstruct [:module_prefix, :__pb_extensions__] field :module_prefix, 1, optional: true, type: :string + + extensions [{1000, 536_870_912}] +end + +defmodule Elixirpb.FieldOptions do + @moduledoc false + use Protobuf, syntax: :proto2 + + @type t :: %__MODULE__{__pb_extensions__: map} + defstruct [:__pb_extensions__] + + extensions [{1000, 536_870_912}] end defmodule Elixirpb.PbExtension do @@ -15,4 +28,5 @@ defmodule Elixirpb.PbExtension do use Protobuf, syntax: :proto2 extend Google.Protobuf.FileOptions, :file, 1047, optional: true, type: Elixirpb.FileOptions + extend Google.Protobuf.FieldOptions, :field, 65007, optional: true, type: Elixirpb.FieldOptions end diff --git a/lib/protobuf/extension.ex b/lib/protobuf/extension.ex index 3cc8b34e..011b0b39 100644 --- a/lib/protobuf/extension.ex +++ b/lib/protobuf/extension.ex @@ -134,6 +134,7 @@ defmodule Protobuf.Extension do if GlobalStore.get(fnum_key, nil) do raise "Extension #{inspect(ext.extendee)}##{fnum} already exists" end + IO.inspect(:stderr, {fnum_key, mod}, label: :extensions) GlobalStore.put(fnum_key, mod) end) diff --git a/lib/protobuf/protoc/generator/message.ex b/lib/protobuf/protoc/generator/message.ex index 146a335b..103ba912 100644 --- a/lib/protobuf/protoc/generator/message.ex +++ b/lib/protobuf/protoc/generator/message.ex @@ -11,6 +11,8 @@ defmodule Protobuf.Protoc.Generator.Message do end def generate(ctx, desc) do + IO.inspect(:stderr, desc, label: :desc) + msg_struct = parse_desc(ctx, desc) IO.inspect(:stderr, msg_struct, label: :message_struct) ctx = %{ctx | namespace: msg_struct[:new_namespace]} @@ -293,13 +295,32 @@ defmodule Protobuf.Protoc.Generator.Message do end defp merge_field_options(opts, f) do - extype_options = Google.Protobuf.FieldOptions.get_extension(f.options, Brex.Elixir.PbExtension, :field) - - IO.inspect(:stderr, {opts, f.options, extype_options}, label: :together) + field_options = + f.options + |> Google.Protobuf.FieldOptions.get_extension(Elixirpb.PbExtension, :field) + |> case do + nil -> nil + elixir_field_options -> + elixir_field_options + # strips :__struct__ + |> Map.from_struct() + |> Enum.flat_map(&get_custom_field_options/1) + |> case do + [] -> nil + custom_opts -> custom_opts + end + end opts - |> Map.put(:packed, f.options.packed) - |> Map.put(:deprecated, f.options.deprecated) - |> Map.put(:options, "#{inspect(extype_options)}") + |> Map.put(:packed, f.options.packed) + |> Map.put(:deprecated, f.options.deprecated) + |> Map.put(:options, field_options) + end + + def get_custom_field_options({:__pb_extensions__, opts}) do + # For now if you want field options to show up in DSL you havee to extend Elixirpb.FieldOptions. + Enum.map(opts, fn {{_extending_message, field}, arg} -> {field, arg} end) end + # Collect existing Elixirpb.FieldOptions (right now no fields though). + def get_custom_field_options({k, v}), do: [{k, v}] end diff --git a/lib/protobuf/protoc/generator/util.ex b/lib/protobuf/protoc/generator/util.ex index a9ac87a5..84ddb41e 100644 --- a/lib/protobuf/protoc/generator/util.ex +++ b/lib/protobuf/protoc/generator/util.ex @@ -49,5 +49,6 @@ defmodule Protobuf.Protoc.Generator.Util do end def print(v) when is_atom(v), do: inspect(v) + def print(v) when is_list(v), do: inspect(v) def print(v), do: v end diff --git a/src/elixir.proto b/src/elixir.proto index 8c5954c4..9393c56a 100644 --- a/src/elixir.proto +++ b/src/elixir.proto @@ -1,24 +1,22 @@ +// This is not working, remove + syntax = "proto2"; // we should call just elixirpb and merge with Tony's // https://github.com/tony612/protobuf-elixir/blob/e1d4a23baa1f51c2da58db24f58a26dc4d6511b2/src/elixirpb.proto package brex.elixir; -import "google/protobuf/descriptor.proto"; +import "elixirpb.proto"; // Define an extension to specify the elixir type generated for the given field. // Field level options // // For example, -// google.protobuf.StringValue my_string = 1 [(brex.elixirpb.field).extype="String.t"]; - -message FieldOptions { - // Specify an elixir type to generate for this field. This will override usual type. - optional string extype = 1; -} +// google.protobuf.StringValue my_string = 1 [(elixirpb.field).extype="String.t"]; -extend google.protobuf.FieldOptions { +extend elixirpb.FieldOptions { // number to change - optional FieldOptions field = 65007; + optional string extype = 1000; + //optional boolean lowercase = 1001; } \ No newline at end of file diff --git a/src/elixirpb.proto b/src/elixirpb.proto index 180cc78b..c2809f54 100644 --- a/src/elixirpb.proto +++ b/src/elixirpb.proto @@ -23,9 +23,20 @@ message FileOptions { // will be "Hello.Request". But with module_prefix "Foo", the message will be // "Foo.Request" optional string module_prefix = 1; + extensions 1000 to max; } extend google.protobuf.FileOptions { optional FileOptions file = 1047; } +message FieldOptions { + // optional string extype = 1; + extensions 1000 to max; +} + +extend google.protobuf.FieldOptions { + // TODO: determine appropriate number + optional FieldOptions field = 65007; +} + diff --git a/test/protobuf/protoc/generator/message_test.exs b/test/protobuf/protoc/generator/message_test.exs index f86df076..310ccb4a 100644 --- a/test/protobuf/protoc/generator/message_test.exs +++ b/test/protobuf/protoc/generator/message_test.exs @@ -176,11 +176,12 @@ defmodule Protobuf.Protoc.Generator.MessageTest do test "generate/2 supports extensions on field options" do ctx = %Context{package: ""} - opts = Google.Protobuf.FieldOptions.new() - custom_opts = Brex.Elixir.FieldOptions.new(extype: "String.t") + field_opts = Google.Protobuf.FieldOptions.new() + elixir_opts = Elixirpb.FieldOptions.new() + custom_opts = Elixirpb.FieldOptions.put_extension(elixir_opts, Brex.Elixir.PbExtension, :extype, "String.t") opts = - Google.Protobuf.FieldOptions.put_extension(opts, Brex.Elixir.PbExtension, :field, custom_opts) + Google.Protobuf.FieldOptions.put_extension(field_opts, Elixirpb.PbExtension, :field, custom_opts) desc = Google.Protobuf.DescriptorProto.new( @@ -190,7 +191,7 @@ defmodule Protobuf.Protoc.Generator.MessageTest do name: "my_string", number: 1, type: :TYPE_MESSAGE, - # type_name: ".google.protobuf.StringValue", + # type_name: ".google.protodescbuf.StringValue", label: :LABEL_OPTIONAL, options: opts ) @@ -198,7 +199,7 @@ defmodule Protobuf.Protoc.Generator.MessageTest do ) {[], [msg]} = Generator.generate(ctx, desc) - assert msg =~ "field :my_string, 1, optional: true, type: :message, options: %Brex.Elixir.FieldOptions{extype: \"String.t\"}\n" + assert msg =~ "field :my_string, 1, optional: true, type: :message, options: [extype: \"String.t\"]\n" end test "generate/2 supports message type field" do From 548ee67251914edb21e51c79e3eccc32649d876f Mon Sep 17 00:00:00 2001 From: Lizzie Paquette Date: Sun, 12 Apr 2020 12:17:02 -0700 Subject: [PATCH 5/7] remove unnecessary changes --- config/config.exs | 3 --- plz.txt | 2 ++ src/elixirpb.proto | 12 ------------ 3 files changed, 2 insertions(+), 15 deletions(-) create mode 100644 plz.txt diff --git a/config/config.exs b/config/config.exs index 819f061a..d2d855e6 100644 --- a/config/config.exs +++ b/config/config.exs @@ -1,4 +1 @@ use Mix.Config - -config :protobuf, extensions: :enabled - diff --git a/plz.txt b/plz.txt new file mode 100644 index 00000000..79cc1fcf --- /dev/null +++ b/plz.txt @@ -0,0 +1,2 @@ +deps/protobuf/src: warning: directory does not exist. +Could not make proto path relative: test/support/wrapper_with_extension.proto: No such file or directory diff --git a/src/elixirpb.proto b/src/elixirpb.proto index c2809f54..9fa51d26 100644 --- a/src/elixirpb.proto +++ b/src/elixirpb.proto @@ -23,20 +23,8 @@ message FileOptions { // will be "Hello.Request". But with module_prefix "Foo", the message will be // "Foo.Request" optional string module_prefix = 1; - extensions 1000 to max; } extend google.protobuf.FileOptions { optional FileOptions file = 1047; } - -message FieldOptions { - // optional string extype = 1; - extensions 1000 to max; -} - -extend google.protobuf.FieldOptions { - // TODO: determine appropriate number - optional FieldOptions field = 65007; -} - From 13438acf4864988a52aa24136a3d04fcfd525e97 Mon Sep 17 00:00:00 2001 From: Lizzie Paquette Date: Sun, 12 Apr 2020 12:41:03 -0700 Subject: [PATCH 6/7] remove extension of extension --- lib/elixir.pb.ex | 6 ---- lib/elixirpb.pb.ex | 18 ++--------- lib/protobuf/extension.ex | 3 +- lib/protobuf/extension/props.ex | 2 +- lib/protobuf/message_props.ex | 2 +- lib/protobuf/protoc/generator/message.ex | 32 ++++++------------- src/elixir.proto | 22 ------------- .../protoc/generator/message_test.exs | 14 +++++--- 8 files changed, 25 insertions(+), 74 deletions(-) delete mode 100644 lib/elixir.pb.ex delete mode 100644 src/elixir.proto diff --git a/lib/elixir.pb.ex b/lib/elixir.pb.ex deleted file mode 100644 index edca4027..00000000 --- a/lib/elixir.pb.ex +++ /dev/null @@ -1,6 +0,0 @@ -defmodule Brex.Elixir.PbExtension do - @moduledoc false - use Protobuf, syntax: :proto2 - - extend Elixirpb.FieldOptions, :extype, 1000, optional: true, type: :string -end diff --git a/lib/elixirpb.pb.ex b/lib/elixirpb.pb.ex index f820cd6a..0d64c696 100644 --- a/lib/elixirpb.pb.ex +++ b/lib/elixirpb.pb.ex @@ -3,24 +3,11 @@ defmodule Elixirpb.FileOptions do use Protobuf, syntax: :proto2 @type t :: %__MODULE__{ - module_prefix: String.t(), - __pb_extensions__: map + module_prefix: String.t() } - defstruct [:module_prefix, :__pb_extensions__] + defstruct [:module_prefix] field :module_prefix, 1, optional: true, type: :string - - extensions [{1000, 536_870_912}] -end - -defmodule Elixirpb.FieldOptions do - @moduledoc false - use Protobuf, syntax: :proto2 - - @type t :: %__MODULE__{__pb_extensions__: map} - defstruct [:__pb_extensions__] - - extensions [{1000, 536_870_912}] end defmodule Elixirpb.PbExtension do @@ -28,5 +15,4 @@ defmodule Elixirpb.PbExtension do use Protobuf, syntax: :proto2 extend Google.Protobuf.FileOptions, :file, 1047, optional: true, type: Elixirpb.FileOptions - extend Google.Protobuf.FieldOptions, :field, 65007, optional: true, type: Elixirpb.FieldOptions end diff --git a/lib/protobuf/extension.ex b/lib/protobuf/extension.ex index 011b0b39..afd9d8dd 100644 --- a/lib/protobuf/extension.ex +++ b/lib/protobuf/extension.ex @@ -134,7 +134,8 @@ defmodule Protobuf.Extension do if GlobalStore.get(fnum_key, nil) do raise "Extension #{inspect(ext.extendee)}##{fnum} already exists" end - IO.inspect(:stderr, {fnum_key, mod}, label: :extensions) + + # IO.inspect(:stderr, {fnum_key, mod}, label: :extensions) GlobalStore.put(fnum_key, mod) end) diff --git a/lib/protobuf/extension/props.ex b/lib/protobuf/extension/props.ex index 60186943..6b9947ac 100644 --- a/lib/protobuf/extension/props.ex +++ b/lib/protobuf/extension/props.ex @@ -5,7 +5,7 @@ defmodule Protobuf.Extension.Props do @moduledoc false @type t :: %__MODULE__{ extendee: module, - field_props: FieldProps.t + field_props: FieldProps.t() } defstruct extendee: nil, field_props: nil diff --git a/lib/protobuf/message_props.ex b/lib/protobuf/message_props.ex index d8b001b1..9fe6166a 100644 --- a/lib/protobuf/message_props.ex +++ b/lib/protobuf/message_props.ex @@ -6,7 +6,7 @@ defmodule Protobuf.MessageProps do @type t :: %__MODULE__{ ordered_tags: [integer], tags_map: %{integer => integer}, - field_props: %{integer => FieldProps.t}, + field_props: %{integer => FieldProps.t()}, field_tags: %{atom => integer}, repeated_fields: [atom], embedded_fields: [atom], diff --git a/lib/protobuf/protoc/generator/message.ex b/lib/protobuf/protoc/generator/message.ex index 103ba912..1365c28d 100644 --- a/lib/protobuf/protoc/generator/message.ex +++ b/lib/protobuf/protoc/generator/message.ex @@ -11,10 +11,7 @@ defmodule Protobuf.Protoc.Generator.Message do end def generate(ctx, desc) do - IO.inspect(:stderr, desc, label: :desc) - msg_struct = parse_desc(ctx, desc) - IO.inspect(:stderr, msg_struct, label: :message_struct) ctx = %{ctx | namespace: msg_struct[:new_namespace]} {nested_enums, nested_msgs} = Enum.unzip(gen_nested_msgs(ctx, desc)) @@ -182,7 +179,6 @@ defmodule Protobuf.Protoc.Generator.Message do end def get_field(ctx, f, nested_maps, oneofs) do - opts = field_options(f) map = nested_maps[f.type_name] @@ -295,32 +291,22 @@ defmodule Protobuf.Protoc.Generator.Message do end defp merge_field_options(opts, f) do - field_options = + custom_options = f.options - |> Google.Protobuf.FieldOptions.get_extension(Elixirpb.PbExtension, :field) + |> Google.Protobuf.FieldOptions.get_extension(Brex.Elixirpb.PbExtension, :field) |> case do - nil -> nil + nil -> + nil + elixir_field_options -> elixir_field_options - # strips :__struct__ |> Map.from_struct() - |> Enum.flat_map(&get_custom_field_options/1) - |> case do - [] -> nil - custom_opts -> custom_opts - end + |> Enum.into([]) end opts - |> Map.put(:packed, f.options.packed) - |> Map.put(:deprecated, f.options.deprecated) - |> Map.put(:options, field_options) - end - - def get_custom_field_options({:__pb_extensions__, opts}) do - # For now if you want field options to show up in DSL you havee to extend Elixirpb.FieldOptions. - Enum.map(opts, fn {{_extending_message, field}, arg} -> {field, arg} end) + |> Map.put(:packed, f.options.packed) + |> Map.put(:deprecated, f.options.deprecated) + |> Map.put(:options, custom_options) end - # Collect existing Elixirpb.FieldOptions (right now no fields though). - def get_custom_field_options({k, v}), do: [{k, v}] end diff --git a/src/elixir.proto b/src/elixir.proto deleted file mode 100644 index 9393c56a..00000000 --- a/src/elixir.proto +++ /dev/null @@ -1,22 +0,0 @@ -// This is not working, remove - -syntax = "proto2"; - -// we should call just elixirpb and merge with Tony's -// https://github.com/tony612/protobuf-elixir/blob/e1d4a23baa1f51c2da58db24f58a26dc4d6511b2/src/elixirpb.proto -package brex.elixir; - -import "elixirpb.proto"; - -// Define an extension to specify the elixir type generated for the given field. - -// Field level options -// -// For example, -// google.protobuf.StringValue my_string = 1 [(elixirpb.field).extype="String.t"]; - -extend elixirpb.FieldOptions { - // number to change - optional string extype = 1000; - //optional boolean lowercase = 1001; -} \ No newline at end of file diff --git a/test/protobuf/protoc/generator/message_test.exs b/test/protobuf/protoc/generator/message_test.exs index 310ccb4a..8bb2b9f4 100644 --- a/test/protobuf/protoc/generator/message_test.exs +++ b/test/protobuf/protoc/generator/message_test.exs @@ -177,11 +177,15 @@ defmodule Protobuf.Protoc.Generator.MessageTest do ctx = %Context{package: ""} field_opts = Google.Protobuf.FieldOptions.new() - elixir_opts = Elixirpb.FieldOptions.new() - custom_opts = Elixirpb.FieldOptions.put_extension(elixir_opts, Brex.Elixir.PbExtension, :extype, "String.t") + custom_opts = Brex.Elixirpb.FieldOptions.new(extype: "String.t") opts = - Google.Protobuf.FieldOptions.put_extension(field_opts, Elixirpb.PbExtension, :field, custom_opts) + Google.Protobuf.FieldOptions.put_extension( + field_opts, + Brex.Elixirpb.PbExtension, + :field, + custom_opts + ) desc = Google.Protobuf.DescriptorProto.new( @@ -199,7 +203,9 @@ defmodule Protobuf.Protoc.Generator.MessageTest do ) {[], [msg]} = Generator.generate(ctx, desc) - assert msg =~ "field :my_string, 1, optional: true, type: :message, options: [extype: \"String.t\"]\n" + + assert msg =~ + "field :my_string, 1, optional: true, type: :message, options: [extype: \"String.t\"]\n" end test "generate/2 supports message type field" do From 47229c4239dc47037c69bd2d8f60267280b57e62 Mon Sep 17 00:00:00 2001 From: Lizzie Paquette <33362730+lizziepaquette@users.noreply.github.com> Date: Mon, 13 Apr 2020 15:38:32 -0700 Subject: [PATCH 7/7] Delete plz.txt --- plz.txt | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 plz.txt diff --git a/plz.txt b/plz.txt deleted file mode 100644 index 79cc1fcf..00000000 --- a/plz.txt +++ /dev/null @@ -1,2 +0,0 @@ -deps/protobuf/src: warning: directory does not exist. -Could not make proto path relative: test/support/wrapper_with_extension.proto: No such file or directory