Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Thrift over HTTP #1

Open
wants to merge 36 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
975fad0
WIP
Ecialo Aug 18, 2020
f27083b
WIP
Ecialo Aug 19, 2020
9b1bc93
WIP
Ecialo Aug 20, 2020
5c06756
WIP
Ecialo Aug 21, 2020
9670db5
error handling WIP
Ecialo Aug 21, 2020
62628c6
exceptions
Ecialo Aug 24, 2020
96d1711
More verbose behaviour spec
Ecialo Aug 24, 2020
e72023d
cleanup
Ecialo Aug 24, 2020
65cfb8c
Correct typespec for void call
Ecialo Aug 25, 2020
e6370e6
Reply header
Ecialo Aug 26, 2020
9021f42
Correct typespec for struct
Ecialo Sep 2, 2020
30b2442
wip http client
Ecialo Sep 3, 2020
0ee89e9
Typespec in generated structs
Ecialo Sep 9, 2020
3de9949
WIP
Ecialo Sep 11, 2020
48b5d0b
collections
Ecialo Sep 14, 2020
08fed26
Generators for enum and collections
Ecialo Sep 15, 2020
20c13b8
fix no field struct problem
Ecialo Sep 15, 2020
3717608
fix
Ecialo Sep 15, 2020
d3696ed
better text
Ecialo Sep 17, 2020
6b3cc88
Merge branch 'http-thrift' of https://github.com/Ecialo/elixir-thrift…
Ecialo Sep 21, 2020
d00eef3
apply nested defaults
Ecialo Sep 24, 2020
2fc7ac0
correct apply defaults
Ecialo Sep 24, 2020
2cefbd9
Merge branch 'http-thrift' of https://github.com/Ecialo/elixir-thrift…
Ecialo Sep 28, 2020
33792f5
typedef wip
Ecialo Sep 29, 2020
aa6bbe9
typedef testdata hooks
Ecialo Sep 30, 2020
6d5b5b7
default empty context in apply defaults
Ecialo Oct 2, 2020
740049f
Merge branch 'http-thrift' of https://github.com/Ecialo/elixir-thrift…
Ecialo Nov 3, 2020
9ce83c5
annotations wip
Ecialo Nov 9, 2020
b349877
annotations
Ecialo Nov 11, 2020
6bf05be
struct with overrides
Ecialo Nov 19, 2020
5532a0d
refinement for option fields in struct
Ecialo Dec 16, 2020
035f9ba
WIP: pass headers in handlers
Ecialo Feb 4, 2021
63d573b
Pass opts in thrift client
Ecialo Feb 8, 2021
0d83a18
Headers now in proper place >_>
Ecialo Feb 8, 2021
27ba617
Pass thrift errors
Ecialo Mar 17, 2021
05acbe4
Merge pull request #2 from Ecialo/client-errors
Ecialo Dec 17, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion example/mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ defmodule Calculator.MixProject do
[
# Note: you will want to replace the next line to get elixir-thrift from either
# Hex or GitHub in your own project.
{:thrift, path: ".."}
{:thrift, path: ".."},
{:httpoison, "~> 1.7.0"}
]
end
end
24 changes: 17 additions & 7 deletions lib/mix/tasks/compile.thrift.ex
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ defmodule Mix.Tasks.Compile.Thrift do
# other settings...
thrift: [
files: Path.wildcard("thrift/**/*.thrift"),
output_path: "lib/generated"
output_path: "lib/generated",
output_test_data: "test/test_data/"
]
]
end
Expand All @@ -64,6 +65,13 @@ defmodule Mix.Tasks.Compile.Thrift do
input_files = Keyword.get(config, :files, [])
output_path = Keyword.get(config, :output_path, "lib")

output_test_data =
Keyword.get(
config,
:output_test_data,
"test/test_data/"
)

parser_opts =
config
|> Keyword.take([:include_paths, :namespace])
Expand All @@ -77,8 +85,8 @@ defmodule Mix.Tasks.Compile.Thrift do

{groups, [] = _diagnostics} ->
groups
|> extract_targets(output_path, opts[:force])
|> generate(manifest(), output_path, opts)
|> extract_targets({output_path, output_test_data}, opts[:force])
|> generate(manifest(), [output_path, output_test_data], opts)

{_groups, diagnostics} ->
{:error, diagnostics}
Expand Down Expand Up @@ -117,8 +125,8 @@ defmodule Mix.Tasks.Compile.Thrift do

@typep mappings :: [{:stale, FileGroup.t(), [Path.t()]} | {:ok, FileGroup.t(), [Path.t()]}]

@spec extract_targets([FileGroup.t()], Path.t(), boolean) :: mappings
defp extract_targets(groups, output_path, force) when is_list(groups) do
@spec extract_targets([FileGroup.t()], {Path.t(), Path.t()}, boolean) :: mappings
defp extract_targets(groups, {output_path, _}, force) when is_list(groups) do
for %FileGroup{initial_file: file} = group <- groups do
targets =
group
Expand All @@ -135,7 +143,7 @@ defmodule Mix.Tasks.Compile.Thrift do

@spec generate(mappings, Path.t(), Path.t(), OptionParser.parsed()) ::
{:ok | :noop | :error, [Diagnostic.t()]}
defp generate(mappings, manifest, output_path, opts) do
defp generate(mappings, manifest, [output_path, output_test_data] = output, opts) do
timestamp = :calendar.universal_time()
verbose = opts[:verbose]

Expand All @@ -157,13 +165,15 @@ defmodule Mix.Tasks.Compile.Thrift do
else
# Ensure we have an output directory and remove old target files.
File.mkdir_p!(output_path)
File.mkdir_p!(output_test_data)

Enum.each(removed, &File.rm/1)

unless Enum.empty?(stale) do
Mix.Utils.compiling_n(length(stale), :thrift)

Enum.each(stale, fn {group, _targets} ->
Thrift.Generator.generate!(group, output_path)
Thrift.Generator.generate!(group, output)
verbose && Mix.shell().info("Compiled #{group.initial_file}")
end)
end
Expand Down
13 changes: 11 additions & 2 deletions lib/mix/tasks/thrift.generate.ex
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ defmodule Mix.Tasks.Thrift.Generate do
# other settings...
thrift: [
include_paths: ["./extra_thrift"],
output_path: "lib/generated"
output_path: "lib/generated",
output_test_data: "test/test_data/"
]
]
end
Expand All @@ -55,12 +56,20 @@ defmodule Mix.Tasks.Thrift.Generate do
{opts, files} =
OptionParser.parse!(
args,
switches: [include: :keep, namespace: :string, out: :string, verbose: :boolean],
switches: [
include: :keep,
namespace: :string,
out: :string,
out_test: :string,
verbose: :boolean
],
aliases: [I: :include, o: :out, v: :verbose]
)

config = Keyword.get(Mix.Project.config(), :thrift, [])
output_path = opts[:out] || Keyword.get(config, :output_path, "lib")
output_test_data = opts[:out_test] || Keyword.get(config, :output_test_data, "lib")

namespace = opts[:namespace] || Keyword.get(config, :namespace)

include_paths =
Expand Down
41 changes: 35 additions & 6 deletions lib/thrift/ast.ex
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,23 @@ defmodule Thrift.AST do
end
end

defmodule Typedef do

@type t :: %Typedef{
line: Thrift.Parser.line(),
annotations: Thrift.Parser.annotations(),
name: atom(),
type: Types.t()
}
@enforce_keys [:name, :type]
defstruct line: nil, annotations: %{}, name: nil, type: nil

def new(name, type) do
%Typedef{name: List.to_atom(name), type: type}
end

end

defmodule TEnum do
@moduledoc """
An enumerated type with named values.
Expand Down Expand Up @@ -528,18 +545,30 @@ defmodule Thrift.AST do
}
end

defp merge(schema, {:typedef, actual_type, type_alias}) do
defp merge(schema, %Typedef{} = typedef) do
%Schema{
schema
| typedefs:
put_new_strict(
schema.typedefs,
List.to_atom(type_alias),
add_namespace_to_type(schema.module, actual_type)
)
put_new_strict(
schema.typedefs,
typedef.name,
add_namespace_to_name(schema.module, typedef)
)
}
end

# defp merge(schema, {:typedef, actual_type, type_alias}) do
# %Schema{
# schema
# | typedefs:
# put_new_strict(
# schema.typedefs,
# List.to_atom(type_alias),
# add_namespace_to_type(schema.module, actual_type)
# )
# }
# end

defp add_namespace_to_name(nil, model) do
model
end
Expand Down
3 changes: 3 additions & 0 deletions lib/thrift/binary/framed/server/http.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
defmodule Thrift.Binary.Framed.Server.HTTP do

end
81 changes: 66 additions & 15 deletions lib/thrift/generator.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ defmodule Thrift.Generator do
Generator,
Generator.ConstantGenerator,
Generator.EnumGenerator,
Generator.StructGenerator
Generator.StructGenerator,
Generator.TestDataGenerator
}

alias Thrift.Parser.FileGroup
Expand All @@ -24,6 +25,7 @@ defmodule Thrift.Generator do
schema
|> Map.put(:file_group, file_group)
|> generate_schema
|> hd()
|> Enum.map(fn {name, _} -> target_path(name) end)
end)
end
Expand All @@ -38,12 +40,12 @@ defmodule Thrift.Generator do
|> Kernel.<>(".ex")
end

def generate!(%FileGroup{} = file_group, output_dir) do
def generate!(%FileGroup{} = file_group, [_output_dir, _output_test_data] = output) do
Enum.flat_map(file_group.schemas, fn {_, schema} ->
schema
|> Map.put(:file_group, file_group)
|> generate_schema
|> write_schema_to_file(output_dir)
|> write_schema_to_file(output)
end)
end

Expand All @@ -62,25 +64,35 @@ defmodule Thrift.Generator do
current_module_file_group = FileGroup.set_current_module(schema.file_group, schema.module)
schema = %Schema{schema | file_group: current_module_file_group}

List.flatten([
generate_enum_modules(schema),
generate_const_modules(schema),
generate_struct_modules(schema),
generate_union_modules(schema),
generate_exception_modules(schema),
generate_services(schema),
generate_behaviours(schema)
])
modules =
List.flatten([
generate_enum_modules(schema),
generate_const_modules(schema),
generate_struct_modules(schema),
generate_union_modules(schema),
generate_exception_modules(schema),
generate_services(schema),
generate_behaviours(schema)
])

test_modules = generate_test_data_modules(schema)
[modules, test_modules]
end

defp write_schema_to_file(module_groups, outputs) do
module_groups
|> Enum.zip(outputs)
|> Enum.map(&perform_write/1)
end

defp write_schema_to_file(generated_modules, output_dir) do
generated_modules
defp perform_write({modules, output}) do
modules
|> resolve_name_collisions
|> Enum.map(fn {name, quoted} ->
filename = target_path(name)
source = Macro.to_string(quoted)

path = Path.join(output_dir, filename)
path = Path.join(output, filename)

path
|> Path.dirname()
Expand Down Expand Up @@ -141,6 +153,45 @@ defmodule Thrift.Generator do
{:defmodule, meta, [name, [do: {:__block__, [], ast1 ++ ast2}]]}
end

defp generate_test_data_modules(schema) do
endless_label = fn label -> Stream.repeatedly(fn -> label end) end
zip_with_label = fn label, stream -> Stream.zip(endless_label.(label), stream) end

typedefs_stream = zip_with_label.(:typedef, schema.typedefs)
structs_stream = zip_with_label.(:struct, schema.structs)
exceptions_stream = zip_with_label.(:exception, schema.exceptions)
unions_stream = zip_with_label.(:union, schema.unions)
enums_stream = zip_with_label.(:enum, schema.enums)

all_streams =
Stream.concat([
typedefs_stream,
structs_stream,
exceptions_stream,
unions_stream,
enums_stream
])

for {label, {key, struct}} <- all_streams do
full_name =
case label do
:typedef ->
thrift_module = Atom.to_string(schema.module)
typedef = key |> Atom.to_string() |> String.capitalize()
name = "#{thrift_module}.#{typedef}" |> String.to_atom()

FileGroup.dest_module(schema.file_group, name)

_otherwise ->
FileGroup.dest_module(schema.file_group, struct)
end

full_test_data_name = TestDataGenerator.test_data_module_from_data_module(full_name)

{full_test_data_name, TestDataGenerator.generate(label, schema, full_name, struct)}
end
end

defp generate_enum_modules(schema) do
for {_, enum} <- schema.enums do
full_name = FileGroup.dest_module(schema.file_group, enum)
Expand Down
Loading