Packages

A collection of utilities for working with Thrift in Elixir. Provides a copy of the Apache Thrift Erlang runtime.

Current section

Files

Jump to
thrift lib mix tasks compile.thrift.ex
Raw

lib/mix/tasks/compile.thrift.ex

defmodule Mix.Tasks.Compile.Thrift do
use Mix.Task
@moduledoc """
Generate Erlang source files from .thrift schema files.
When this task runs, it first checks the modification times of all source
files that were generated by the set of .thrift files. If the generated
files are older than the .thrift file that generated them, this task will
skip regenerating them.
## Command line options
* `--force` - forces compilation regardless of modification times
## Configuration
* `:thrift_files` - list of .thrift schema files to compile
* `:thrift_output` - output directory into which the generated Erlang
source file will be generated. Defaults to `"src"`.
* `:thrift_options` - list of additional options that will be passed to
the Thrift compiler.
* `:thrift_executable` - thrift compiler executable. Defaults to `"thrift"`.
* `:thrift_version` - thrift compiler `Version` requirement
"""
@spec run(OptionParser.argv) :: :ok | :noop
def run(args) do
{opts, _, _} = OptionParser.parse(args, switches: [force: :boolean])
config = Mix.Project.config
thrift_files = Keyword.get(config, :thrift_files, [])
thrift_executable = Keyword.get(config, :thrift_executable, "thrift")
thrift_options = Keyword.get(config, :thrift_options, [])
thrift_version = Keyword.get(config, :thrift_version)
output_dir = Keyword.get(config, :thrift_output, "src")
stale_files = Enum.filter(thrift_files, fn file ->
opts[:force] || stale?(file, output_dir)
end)
unless(System.find_executable(thrift_executable)) do
Mix.raise "`#{thrift_executable}` not found in the current path"
end
if(thrift_version && !Enum.empty?(stale_files)) do
v = get_thrift_version(thrift_executable)
unless(Version.match?(v, thrift_version)) do
Mix.raise "Unsupported Thrift version #{v} (requires #{thrift_version})"
end
end
unless Enum.empty?(stale_files) do
File.mkdir_p!(output_dir)
options = build_options(output_dir, thrift_options)
Enum.each stale_files, &generate(thrift_executable, options, &1)
end
end
defp get_thrift_version(exec) do
case System.cmd(exec, ~w[-version]) do
{s, 0} -> hd(Regex.run(~r/\b(\d+\.\d+\.\d+)\b/, s, capture: :first) || [])
{_, e} -> Mix.raise "Failed to execute `#{exec} -version` (error #{e})"
end
end
defp get_generated_files(thrift_file, output_dir) do
basename = Path.basename(thrift_file, ".thrift")
pattern = basename <> "_{constants,thrift,types}.{erl,hrl}"
Mix.Utils.extract_files([output_dir], pattern)
end
defp stale?(thrift_file, output_dir) do
targets = get_generated_files(thrift_file, output_dir)
Enum.empty?(targets) || Mix.Utils.stale?([thrift_file], targets)
end
defp build_options(output_dir, user_options) do
opts = ~w[--out] ++ [output_dir]
unless Enum.member?(user_options, "--gen") do
opts = opts ++ ~w[--gen erl]
end
opts ++ user_options
end
defp generate(exec, options, thrift_file) do
args = options ++ [thrift_file]
case System.cmd(exec, args) do
{_, 0} -> Mix.shell.info "Compiled #{thrift_file}"
{_, e} -> Mix.shell.error "Failed to compile #{thrift_file} (error #{e})"
end
end
end