11defmodule Mix.Compilers.Elixir do
22 @ moduledoc false
33
4- @ manifest_vsn :v2
4+ @ manifest_vsn :v3
55
66 @ doc """
77 Compiles stale Elixir files.
@@ -18,10 +18,10 @@ defmodule Mix.Compilers.Elixir do
1818 def compile ( manifest , srcs , skip , exts , dest , force , on_start ) do
1919 keep = srcs -- skip
2020 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 )
2222
2323 removed =
24- for { _b , _m , _k , source , _cd , _rd , _f , _bin } <- all_entries ,
24+ for { source , _files } <- all_sources ,
2525 not ( source in all ) ,
2626 do: source
2727
@@ -32,43 +32,43 @@ defmodule Mix.Compilers.Elixir do
3232 all
3333 else
3434 modified = Mix.Utils . last_modified ( manifest )
35- all_mtimes = mtimes ( all_entries )
35+ all_mtimes = mtimes ( all_sources )
3636
3737 # Otherwise let's start with the new ones
3838 # plus the ones that have changed
3939 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 ) ,
4141 do: source )
4242 ++
43- for ( { _b , _m , _k , source , _cd , _rd , files , _bin } <- all_entries ,
43+ for ( { source , files } <- all_sources ,
4444 times = Enum . map ( [ source | files ] , & Map . fetch! ( all_mtimes , & 1 ) ) ,
4545 Mix.Utils . stale? ( times , [ modified ] ) ,
4646 do: source )
4747 end
4848
49+ sources = update_stale_sources ( all_sources , removed , changed )
4950 { entries , changed } = remove_stale_entries ( all_entries , removed ++ changed )
5051 stale = changed -- removed
5152
53+ new_entries = entries ++ skip_entries
54+ new_sources = Map . merge ( sources , skip_sources )
55+
5256 cond do
5357 stale != [ ] ->
54- compile_manifest ( manifest , entries ++ skip_entries , stale , dest , on_start )
58+ compile_manifest ( manifest , new_entries , new_sources , stale , dest , on_start )
5559 :ok
5660 removed != [ ] ->
57- write_manifest ( manifest , entries ++ skip_entries )
61+ write_manifest ( manifest , new_entries , new_sources )
5862 :ok
5963 true ->
6064 :noop
6165 end
6266 end
6367
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 )
7272 end )
7373 end )
7474 end
@@ -77,22 +77,24 @@ defmodule Mix.Compilers.Elixir do
7777 Removes compiled files.
7878 """
7979 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
8285 end
83- :ok
8486 end
8587
8688 @ doc """
8789 Returns protocols and implementations for the given manifest.
8890 """
8991 def protocols_and_impls ( manifest ) do
90- for { _ , module , kind , _ , _ , _ , _ , _ } <- read_manifest ( manifest ) ,
92+ for { _ , module , kind , _ , _ , _ , _ } <- read_manifest ( manifest ) ,
9193 match? ( :protocol , kind ) or match? ( { :impl , _ } , kind ) ,
9294 do: { module , kind }
9395 end
9496
95- defp compile_manifest ( manifest , entries , stale , dest , on_start ) do
97+ defp compile_manifest ( manifest , entries , sources , stale , dest , on_start ) do
9698 Mix.Project . ensure_structure ( )
9799 true = Code . prepend_path ( dest )
98100
@@ -101,16 +103,16 @@ defmodule Mix.Compilers.Elixir do
101103
102104 # Starts a server responsible for keeping track which files
103105 # 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 )
105107
106108 try do
107109 _ = Kernel.ParallelCompiler . files :lists . usort ( stale ) ,
108110 each_module: & each_module ( pid , dest , cwd , & 1 , & 2 , & 3 ) ,
109111 each_file: & each_file ( & 1 ) ,
110112 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 }
114116 end
115117 after
116118 Agent . stop ( pid , :normal , :infinity )
@@ -140,8 +142,12 @@ defmodule Mix.Compilers.Elixir do
140142 kind = detect_kind ( module )
141143 source = Path . relative_to ( source , cwd )
142144 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
145151 end
146152
147153 defp detect_kind ( module ) do
@@ -163,12 +169,16 @@ defmodule Mix.Compilers.Elixir do
163169 do: relative
164170 end
165171
166- defp each_file ( file ) do
167- Mix . shell . info "Compiled #{ file } "
172+ defp each_file ( source ) do
173+ Mix . shell . info "Compiled #{ source } "
168174 end
169175
170176 ## Resolution
171177
178+ defp update_stale_sources ( sources , removed , changed ) do
179+ Enum . reduce changed , Map . drop ( sources , removed ) , & Map . put ( & 2 , & 1 , [ ] )
180+ end
181+
172182 # This function receives the manifest entries and some source
173183 # files that have changed. It then, recursively, figures out
174184 # all the files that changed (via the module dependencies) and
@@ -193,7 +203,7 @@ defmodule Mix.Compilers.Elixir do
193203 end
194204 end
195205
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 ,
197207 { rest , stale , removed } ) do
198208 cond do
199209 # If I changed in disk or have a compile time dependency
@@ -225,30 +235,40 @@ defmodule Mix.Compilers.Elixir do
225235 end
226236
227237 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 } ->
230240 if String . starts_with? ( source , keep_paths ) do
231- { [ entry | keep ] , skip }
241+ { [ entry | keep ] , skip , keep_sources , skip_sources }
232242 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 ) }
234250 end
235251 end
236252 end
237253
238- defp write_manifest ( manifest , [ ] ) do
254+ defp write_manifest ( manifest , [ ] , sources ) when sources == % { } do
239255 File . rm ( manifest )
240256 :ok
241257 end
242258
243- defp write_manifest ( manifest , entries ) do
259+ defp write_manifest ( manifest , entries , sources ) do
244260 File . mkdir_p! ( Path . dirname ( manifest ) )
245261
246262 File . open! ( manifest , [ :write ] , fn device ->
247263 :io . format ( device , '~p.~n' , [ @ manifest_vsn ] )
248264
249- Enum . map entries , fn { beam , _ , _ , _ , _ , _ , _ , binary } = entry ->
265+ Enum . each entries , fn { beam , _ , _ , _ , _ , _ , binary } = entry ->
250266 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 ] )
252272 end
253273
254274 :ok
0 commit comments