1
1
defmodule Mix.Compilers.Elixir do
2
2
@ moduledoc false
3
3
4
- @ manifest_vsn :v2
4
+ @ manifest_vsn :v3
5
5
6
6
@ doc """
7
7
Compiles stale Elixir files.
@@ -18,10 +18,10 @@ defmodule Mix.Compilers.Elixir do
18
18
def compile ( manifest , srcs , skip , exts , dest , force , on_start ) do
19
19
keep = srcs -- skip
20
20
all = Mix.Utils . extract_files ( keep , exts )
21
- { all_entries , skip_entries } = parse_manifest ( manifest , keep )
21
+ { all_entries , skip_entries , all_sources , skip_sources } = parse_manifest ( manifest , keep )
22
22
23
23
removed =
24
- for { _b , _m , _k , source , _cd , _rd , _f , _bin } <- all_entries ,
24
+ for { source , _files } <- all_sources ,
25
25
not ( source in all ) ,
26
26
do: source
27
27
@@ -32,43 +32,43 @@ defmodule Mix.Compilers.Elixir do
32
32
all
33
33
else
34
34
modified = Mix.Utils . last_modified ( manifest )
35
- all_mtimes = mtimes ( all_entries )
35
+ all_mtimes = mtimes ( all_sources )
36
36
37
37
# Otherwise let's start with the new ones
38
38
# plus the ones that have changed
39
39
for ( source <- all ,
40
- not Enum . any? ( all_entries , fn { _b , _m , _k , s , _cd , _rd , _f , _bin } -> s == source end ) ,
40
+ not Map . has_key? ( all_sources , source ) ,
41
41
do: source )
42
42
++
43
- for ( { _b , _m , _k , source , _cd , _rd , files , _bin } <- all_entries ,
43
+ for ( { source , files } <- all_sources ,
44
44
times = Enum . map ( [ source | files ] , & Map . fetch! ( all_mtimes , & 1 ) ) ,
45
45
Mix.Utils . stale? ( times , [ modified ] ) ,
46
46
do: source )
47
47
end
48
48
49
+ sources = update_stale_sources ( all_sources , removed , changed )
49
50
{ entries , changed } = remove_stale_entries ( all_entries , removed ++ changed )
50
51
stale = changed -- removed
51
52
53
+ new_entries = entries ++ skip_entries
54
+ new_sources = Map . merge ( sources , skip_sources )
55
+
52
56
cond do
53
57
stale != [ ] ->
54
- compile_manifest ( manifest , entries ++ skip_entries , stale , dest , on_start )
58
+ compile_manifest ( manifest , new_entries , new_sources , stale , dest , on_start )
55
59
:ok
56
60
removed != [ ] ->
57
- write_manifest ( manifest , entries ++ skip_entries )
61
+ write_manifest ( manifest , new_entries , new_sources )
58
62
:ok
59
63
true ->
60
64
:noop
61
65
end
62
66
end
63
67
64
- defp mtimes ( entries ) do
65
- Enum . reduce ( entries , % { } , fn { _b , _m , _k , source , _cd , _rd , files , _bin } , dict ->
66
- Enum . reduce ( [ source | files ] , dict , fn file , dict ->
67
- if Map . has_key? ( dict , file ) do
68
- dict
69
- else
70
- Map . put ( dict , file , Mix.Utils . last_modified ( file ) )
71
- end
68
+ defp mtimes ( sources ) do
69
+ Enum . reduce ( sources , % { } , fn { source , files } , map ->
70
+ Enum . reduce ( [ source | files ] , map , fn file , map ->
71
+ Map . put_new_lazy ( map , file , fn -> Mix.Utils . last_modified ( file ) end )
72
72
end )
73
73
end )
74
74
end
@@ -77,22 +77,24 @@ defmodule Mix.Compilers.Elixir do
77
77
Removes compiled files.
78
78
"""
79
79
def clean ( manifest ) do
80
- Enum . map read_manifest ( manifest ) , fn { beam , _ , _ , _ , _ , _ , _ , _ } ->
81
- File . rm ( beam )
80
+ Enum . each read_manifest ( manifest ) , fn
81
+ { beam , _ , _ , _ , _ , _ , _ } ->
82
+ File . rm ( beam )
83
+ { _ , _ } ->
84
+ :ok
82
85
end
83
- :ok
84
86
end
85
87
86
88
@ doc """
87
89
Returns protocols and implementations for the given manifest.
88
90
"""
89
91
def protocols_and_impls ( manifest ) do
90
- for { _ , module , kind , _ , _ , _ , _ , _ } <- read_manifest ( manifest ) ,
92
+ for { _ , module , kind , _ , _ , _ , _ } <- read_manifest ( manifest ) ,
91
93
match? ( :protocol , kind ) or match? ( { :impl , _ } , kind ) ,
92
94
do: { module , kind }
93
95
end
94
96
95
- defp compile_manifest ( manifest , entries , stale , dest , on_start ) do
97
+ defp compile_manifest ( manifest , entries , sources , stale , dest , on_start ) do
96
98
Mix.Project . ensure_structure ( )
97
99
true = Code . prepend_path ( dest )
98
100
@@ -101,16 +103,16 @@ defmodule Mix.Compilers.Elixir do
101
103
102
104
# Starts a server responsible for keeping track which files
103
105
# were compiled and the dependencies between them.
104
- { :ok , pid } = Agent . start_link ( fn -> entries end )
106
+ { :ok , pid } = Agent . start_link ( fn -> { entries , sources } end )
105
107
106
108
try do
107
109
_ = Kernel.ParallelCompiler . files :lists . usort ( stale ) ,
108
110
each_module: & each_module ( pid , dest , cwd , & 1 , & 2 , & 3 ) ,
109
111
each_file: & each_file ( & 1 ) ,
110
112
dest: dest
111
- Agent . cast pid , fn entries ->
112
- write_manifest ( manifest , entries )
113
- entries
113
+ Agent . cast pid , fn { entries , sources } ->
114
+ write_manifest ( manifest , entries , sources )
115
+ { entries , sources }
114
116
end
115
117
after
116
118
Agent . stop ( pid , :normal , :infinity )
@@ -140,8 +142,12 @@ defmodule Mix.Compilers.Elixir do
140
142
kind = detect_kind ( module )
141
143
source = Path . relative_to ( source , cwd )
142
144
files = get_external_resources ( module , cwd )
143
- tuple = { beam , module , kind , source , compile , runtime , files , binary }
144
- Agent . cast pid , & :lists . keystore ( beam , 1 , & 1 , tuple )
145
+
146
+ Agent . cast pid , fn { entries , sources } ->
147
+ entries = List . keystore ( entries , beam , 0 , { beam , module , kind , source , compile , runtime , binary } )
148
+ sources = Map . update ( sources , source , files , & files ++ & 1 )
149
+ { entries , sources }
150
+ end
145
151
end
146
152
147
153
defp detect_kind ( module ) do
@@ -163,12 +169,16 @@ defmodule Mix.Compilers.Elixir do
163
169
do: relative
164
170
end
165
171
166
- defp each_file ( file ) do
167
- Mix . shell . info "Compiled #{ file } "
172
+ defp each_file ( source ) do
173
+ Mix . shell . info "Compiled #{ source } "
168
174
end
169
175
170
176
## Resolution
171
177
178
+ defp update_stale_sources ( sources , removed , changed ) do
179
+ Enum . reduce changed , Map . drop ( sources , removed ) , & Map . put ( & 2 , & 1 , [ ] )
180
+ end
181
+
172
182
# This function receives the manifest entries and some source
173
183
# files that have changed. It then, recursively, figures out
174
184
# all the files that changed (via the module dependencies) and
@@ -193,7 +203,7 @@ defmodule Mix.Compilers.Elixir do
193
203
end
194
204
end
195
205
196
- defp remove_stale_entry ( { beam , module , _kind , source , compile , runtime , _f , _bin } = entry ,
206
+ defp remove_stale_entry ( { beam , module , _kind , source , compile , runtime , _bin } = entry ,
197
207
{ rest , stale , removed } ) do
198
208
cond do
199
209
# If I changed in disk or have a compile time dependency
@@ -225,30 +235,40 @@ defmodule Mix.Compilers.Elixir do
225
235
end
226
236
227
237
defp parse_manifest ( manifest , keep_paths ) do
228
- Enum . reduce read_manifest ( manifest ) , { [ ] , [ ] } , fn
229
- { _ , _ , _ , source , _ , _ , _ , _ } = entry , { keep , skip } ->
238
+ Enum . reduce read_manifest ( manifest ) , { [ ] , [ ] , % { } , % { } } , fn
239
+ { _ , _ , _ , source , _ , _ , _ } = entry , { keep , skip , keep_sources , skip_sources } ->
230
240
if String . starts_with? ( source , keep_paths ) do
231
- { [ entry | keep ] , skip }
241
+ { [ entry | keep ] , skip , keep_sources , skip_sources }
232
242
else
233
- { keep , [ entry | skip ] }
243
+ { keep , [ entry | skip ] , keep_sources , skip_sources }
244
+ end
245
+ { source , files } , { keep , skip , keep_sources , skip_sources } ->
246
+ if String . starts_with? ( source , keep_paths ) do
247
+ { keep , skip , Map . put ( keep_sources , source , files ) , skip_sources }
248
+ else
249
+ { keep , skip , keep_sources , Map . put ( skip_sources , source , files ) }
234
250
end
235
251
end
236
252
end
237
253
238
- defp write_manifest ( manifest , [ ] ) do
254
+ defp write_manifest ( manifest , [ ] , sources ) when sources == % { } do
239
255
File . rm ( manifest )
240
256
:ok
241
257
end
242
258
243
- defp write_manifest ( manifest , entries ) do
259
+ defp write_manifest ( manifest , entries , sources ) do
244
260
File . mkdir_p! ( Path . dirname ( manifest ) )
245
261
246
262
File . open! ( manifest , [ :write ] , fn device ->
247
263
:io . format ( device , '~p.~n' , [ @ manifest_vsn ] )
248
264
249
- Enum . map entries , fn { beam , _ , _ , _ , _ , _ , _ , binary } = entry ->
265
+ Enum . each entries , fn { beam , _ , _ , _ , _ , _ , binary } = entry ->
250
266
if binary , do: File . write! ( beam , binary )
251
- :io . format ( device , '~p.~n' , [ put_elem ( entry , 7 , nil ) ] )
267
+ :io . format ( device , '~p.~n' , [ put_elem ( entry , 6 , nil ) ] )
268
+ end
269
+
270
+ Enum . each sources , fn { _ , _ } = entry ->
271
+ :io . format ( device , '~p.~n' , [ entry ] )
252
272
end
253
273
254
274
:ok
0 commit comments