@@ -45,6 +45,12 @@ defmodule Mix.Tasks.Escript.Build do
45
45
* `:embed_elixir` - if `true` embed elixir and its children apps
46
46
(`ex_unit`, `mix`, etc.) mentioned in the `:applications` list inside the
47
47
`application` function in `mix.exs`.
48
+
49
+ Defaults to `true` for Elixir projects.
50
+
51
+ * `:consolidate_protocols` - if `true`, all protocols will be consolidated
52
+ before being embedded into the escript.
53
+
48
54
Defaults to `true` for Elixir projects.
49
55
50
56
* `:shebang` - shebang interpreter directive used to execute the escript.
@@ -86,18 +92,26 @@ defmodule Mix.Tasks.Escript.Build do
86
92
Mix.Task . run :compile , args
87
93
end
88
94
89
- escriptize ( Mix.Project . config , opts [ :force ] )
95
+ project = Mix.Project . config
96
+ language = Keyword . get ( project , :language , :elixir )
97
+ should_consolidate =
98
+ Keyword . get ( project , :consolidate_protocols , language == :elixir )
99
+
100
+ if should_consolidate do
101
+ Mix.Task . run "compile.protocols" , [ ]
102
+ end
103
+
104
+ escriptize ( project , language , opts [ :force ] , should_consolidate )
90
105
end
91
106
92
- defp escriptize ( project , force ) do
107
+ defp escriptize ( project , language , force , should_consolidate ) do
93
108
escript_opts = project [ :escript ] || [ ]
94
109
95
110
script_name = to_string ( escript_opts [ :name ] || project [ :app ] )
96
111
filename = escript_opts [ :path ] || script_name
97
112
main = escript_opts [ :main_module ]
98
113
app = Keyword . get ( escript_opts , :app , project [ :app ] )
99
114
files = project_files ( )
100
- language = Keyword . get ( project , :language , :elixir )
101
115
102
116
escript_mod = String . to_atom ( Atom . to_string ( app ) <> "_escript" )
103
117
@@ -111,9 +125,19 @@ defmodule Mix.Tasks.Escript.Build do
111
125
"in your project configuration (under `:escript` option) to a module that implements main/1"
112
126
113
127
force || Mix.Utils . stale? ( files , [ filename ] ) ->
128
+ beam_paths =
129
+ [ files , deps_files ( ) , core_files ( escript_opts , language ) ]
130
+ |> Stream . concat
131
+ |> prepare_beam_paths
132
+
133
+ if should_consolidate do
134
+ beam_paths =
135
+ Path . wildcard ( consolidated_path <> "/*" )
136
+ |> prepare_beam_paths ( beam_paths )
137
+ end
138
+
114
139
tuples = gen_main ( escript_mod , main , app , language ) ++
115
- to_tuples ( files ) ++ deps_tuples ( ) ++
116
- embed_tuples ( escript_opts , language )
140
+ read_beams ( beam_paths )
117
141
118
142
case :zip . create 'mem' , tuples , [ :memory ] do
119
143
{ :ok , { 'mem' , zip } } ->
@@ -136,7 +160,7 @@ defmodule Mix.Tasks.Escript.Build do
136
160
end
137
161
end
138
162
139
- defp project_files do
163
+ defp project_files ( ) do
140
164
get_files ( Mix.Project . app_path )
141
165
end
142
166
@@ -145,29 +169,19 @@ defmodule Mix.Tasks.Escript.Build do
145
169
( Path . wildcard ( "#{ app } /priv/**/*" ) |> Enum . filter ( & File . regular? / 1 ) )
146
170
end
147
171
148
- defp get_tuples ( app ) do
149
- get_files ( app ) |> to_tuples
150
- end
151
-
152
- defp to_tuples ( files ) do
153
- for f <- files do
154
- { String . to_char_list ( Path . basename ( f ) ) , File . read! ( f ) }
155
- end
156
- end
157
-
158
172
defp set_perms ( filename ) do
159
173
stat = File . stat! ( filename )
160
174
:ok = File . chmod ( filename , stat . mode ||| 0o111 )
161
175
end
162
176
163
- defp deps_tuples do
177
+ defp deps_files ( ) do
164
178
deps = Mix.Dep . loaded ( env: Mix . env ) || [ ]
165
- Enum . flat_map ( deps , fn dep -> get_tuples ( dep . opts [ :build ] ) end )
179
+ Enum . flat_map ( deps , fn dep -> get_files ( dep . opts [ :build ] ) end )
166
180
end
167
181
168
- defp embed_tuples ( escript_opts , language ) do
182
+ defp core_files ( escript_opts , language ) do
169
183
if Keyword . get ( escript_opts , :embed_elixir , language == :elixir ) do
170
- Enum . flat_map [ :elixir | extra_apps ( ) ] , & app_tuples ( & 1 )
184
+ Enum . flat_map [ :elixir | extra_apps ( ) ] , & app_files / 1
171
185
else
172
186
[ ]
173
187
end
@@ -184,13 +198,28 @@ defmodule Mix.Tasks.Escript.Build do
184
198
Enum . filter ( extra_apps || [ ] , & ( & 1 in [ :eex , :ex_unit , :mix , :iex , :logger ] ) )
185
199
end
186
200
187
- defp app_tuples ( app ) do
201
+ defp app_files ( app ) do
188
202
case :code . where_is_file ( '#{ app } .app' ) do
189
203
:non_existing -> Mix . raise "Could not find application #{ app } "
190
- file -> get_tuples ( Path . dirname ( Path . dirname ( file ) ) )
204
+ file -> get_files ( Path . dirname ( Path . dirname ( file ) ) )
191
205
end
192
206
end
193
207
208
+ defp prepare_beam_paths ( paths , dict \\ HashDict . new ) do
209
+ paths
210
+ |> Enum . map ( & { Path . basename ( & 1 ) , & 1 } )
211
+ |> Enum . into ( dict )
212
+ end
213
+
214
+ defp read_beams ( items ) do
215
+ items
216
+ |> Enum . map ( fn { basename , beam_path } ->
217
+ { String . to_char_list ( basename ) , File . read! ( beam_path ) }
218
+ end )
219
+ end
220
+
221
+ defp consolidated_path , do: Mix.Tasks.Compile.Protocols . default_path
222
+
194
223
defp build_comment ( user_comment ) do
195
224
"%% #{ user_comment } \n "
196
225
end
0 commit comments