-
Notifications
You must be signed in to change notification settings - Fork 1
/
thrift.ex
128 lines (102 loc) · 3.75 KB
/
thrift.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
defmodule Mix.Tasks.Compile.Thrift do
@moduledoc """
Provides a mix task for compiling Thrift IDL files to Erlang.
Once Thrash is
compiled, you can execute `mix compile.thrift` to generate Erlang code
(a required precursor for Thrash) from your Thrift IDL files (i.e.,
`.thrift` files). By default, `mix compile.thrift` assumes that your
IDL files are in the `thrift` directory and that the output should go
in the `src` directory.
The following environment variables modify the behavior of `mix
compile.thrift`.
* `THRIFT` - Path to the `thrift` binary (default: `thrift`).
* `THRIFT_INPUT_DIR` - Directory containing your `.thrift` files
(default: `thrift`).
* `THRIFT_OUTPUT_DIR` - Directory in which generated Erlang
source code is placed (default: `src`).
* `FORCE_THRIFT` - Set to any of `["TRUE", "true", "1"]` to force
execution of `thrift`. By default, the task automatically determines
if it is necessary to execute `thrift` based on the mtimes of the
files in the input and output directories.
Prepend `:thrift` to the list of compilers in your project
and this task will run automatically as needed.
```
defmodule MyProject.Mixfile do
use Mix.Project
def project do
[app: :my_project,
# usual stuff ..
# prepend thrift to the usual list of compilers
compilers: [:thrift] ++ Mix.compilers
# ...
]
end
end
```
Run `mix deps.compile` first to ensure that the `compile.thrift` task
is available.
"""
use Mix.Task
def run(_args) do
options = get_env_options()
File.mkdir_p!(options[:thrift_output_dir])
input_files = thrift_files(options[:thrift_input_dir])
output_files = generated_files(options[:thrift_output_dir])
if require_compile?(options[:force_thrift], input_files, output_files) do
run_thrift(options[:thrift],
options[:thrift_input_dir],
options[:thrift_output_dir])
end
end
defp get_env_options() do
%{
thrift: System.get_env("THRIFT") || "thrift",
thrift_input_dir: System.get_env("THRIFT_INPUT_DIR") || "thrift",
thrift_output_dir: System.get_env("THRIFT_OUTPUT_DIR") || "src",
force_thrift: force_thrift?(System.get_env("FORCE_THRIFT") || false)
}
end
defp thrift_files(thrift_input_dir) do
Mix.Utils.extract_files([thrift_input_dir], ["thrift"])
end
defp run_thrift_on(f, thrift_bin, thrift_output_dir) do
cmd = thrift_bin <> " -o #{thrift_output_dir} --gen erl #{f}"
IO.puts cmd
0 = Mix.shell.cmd(cmd)
end
defp run_thrift(thrift_bin, thrift_input_dir, thrift_output_dir) do
thrift_input_dir
|> thrift_files
|> Enum.each(fn(f) -> run_thrift_on(f, thrift_bin, thrift_output_dir) end)
end
defp generated_files(output_dir) do
Mix.Utils.extract_files([Path.join(output_dir, "gen-erl")], ["hrl", "erl"])
end
defp force_thrift?("TRUE"), do: true
defp force_thrift?("true"), do: true
defp force_thrift?("1"), do: true
defp force_thrift?(_), do: false
defp require_compile?(true, _, _), do: true
defp require_compile?(false, _, []), do: true
defp require_compile?(false, input_files, output_files) do
input_stats = stats_by_mtime(input_files)
output_stats = stats_by_mtime(output_files)
most_recent(input_stats) > least_recent(output_stats)
end
defp stats_by_mtime(files) do
Enum.sort_by(file_stats(files), fn(stat) -> stat.mtime end)
end
defp file_stats(files) do
Enum.map(files, fn(file) ->
File.stat!(file, time: :posix)
end)
end
defp most_recent([]), do: 0
defp most_recent([h | _t]), do: h.mtime
# note x < :infinity is true for any integer
defp least_recent([]), do: :infinity
defp least_recent(list) do
last = List.last(list)
last.mtime
end
end