@@ -73,7 +73,31 @@ defmodule Mix.Dep.Converger do
7373 def converge ( acc , lock , opts , callback ) do
7474 { deps , acc , lock } = all ( acc , lock , opts , callback )
7575 if remote = Mix.RemoteConverger . get ( ) , do: remote . post_converge ( )
76- { topological_sort ( deps ) , acc , lock }
76+ sorted_deps = topological_sort ( deps )
77+ warn_on_unneeded_deps_overrides ( sorted_deps )
78+ { sorted_deps , acc , lock }
79+ end
80+
81+ defp warn_on_unneeded_deps_overrides ( [ % { app: app , opts: opts } = dep | rest ] ) do
82+ override = Keyword . get ( opts , :override , false )
83+
84+ if is_list ( override ) do
85+ Enum . each ( override , fn overridden_app ->
86+ # Since we used a topological sort, if someone depends on dep, it will come after dep
87+ with % { deps: deps } <- Enum . find ( rest , & ( & 1 . app == overridden_app ) ) ,
88+ true <- Enum . any? ( deps , & ( & 1 . app == app ) ) do
89+ :ok
90+ else
91+ _ -> warn_uneeded_override ( dep , overridden_app )
92+ end
93+ end )
94+ end
95+
96+ warn_on_unneeded_deps_overrides ( rest )
97+ end
98+
99+ defp warn_on_unneeded_deps_overrides ( [ ] ) do
100+ :ok
77101 end
78102
79103 defp all ( acc , lock , opts , callback ) do
@@ -152,11 +176,10 @@ defmodule Mix.Dep.Converger do
152176
153177 defp init_all ( main , apps , rest , lock , callback , locked? , env_target , cache ) do
154178 state = % { locked?: locked? , env_target: env_target , cache: cache , callback: callback }
155- { deps , _kept , _optional , rest , lock } = all ( main , [ ] , [ ] , [ ] , apps , [ ] , rest , lock , state )
156- deps = Enum . reverse ( deps )
179+ { deps , _kept , _optional , rest , lock } = all ( main , nil , [ ] , [ ] , [ ] , apps , [ ] , rest , lock , state )
157180 # When traversing dependencies, we keep skipped ones to
158181 # find conflicts. We remove them now after traversal.
159- { deps , _ } = Mix.Dep.Loader . split_by_env_and_target ( deps , env_target )
182+ { deps , _ } = deps |> Enum . reverse ( ) |> Mix.Dep.Loader . split_by_env_and_target ( env_target )
160183 { deps , rest , lock }
161184 end
162185
@@ -199,19 +222,19 @@ defmodule Mix.Dep.Converger do
199222 # Now, since "d" was specified in a parent project, no
200223 # exception is going to be raised since d is considered
201224 # to be the authoritative source.
202- defp all ( [ dep | t ] , acc , kept , upper , breadths , optional , rest , lock , state ) do
203- case match_deps ( acc , upper , dep , state . env_target ) do
225+ defp all ( [ dep | t ] , parent , acc , kept , upper , breadths , optional , rest , lock , state ) do
226+ case match_deps ( parent , acc , upper , dep , state . env_target ) do
204227 { :replace , dep , acc } ->
205- all ( [ dep | t ] , acc , kept , upper , breadths , optional , rest , lock , state )
228+ all ( [ dep | t ] , parent , acc , kept , upper , breadths , optional , rest , lock , state )
206229
207230 { :match , acc } ->
208- all ( t , acc , kept , upper , breadths , optional , rest , lock , state )
231+ all ( t , parent , acc , kept , upper , breadths , optional , rest , lock , state )
209232
210233 :skip ->
211234 # We still keep skipped dependencies around to detect conflicts.
212235 # They must be rejected after every all iteration but they are not
213236 # included in the list of kept dependencies.
214- all ( t , [ dep | acc ] , kept , upper , breadths , optional , rest , lock , state )
237+ all ( t , parent , [ dep | acc ] , kept , upper , breadths , optional , rest , lock , state )
215238
216239 :nomatch ->
217240 { % { app: app , deps: deps , opts: opts } = dep , rest , lock } =
@@ -234,19 +257,21 @@ defmodule Mix.Dep.Converger do
234257 # no longer a dependency. Add it back for traversal.
235258 { no_longer_optional , optional } = Enum . split_with ( optional , & ( & 1 . app == app ) )
236259 t = no_longer_optional ++ t
260+ acc = [ dep | acc ]
237261
238262 { acc , kept , optional , rest , lock } =
239- all ( t , [ dep | acc ] , [ dep . app | kept ] , upper , breadths , optional , rest , lock , state )
263+ all ( t , parent , acc , [ dep . app | kept ] , upper , breadths , optional , rest , lock , state )
240264
241265 # Now traverse all parent dependencies and see if we have any optional dependency.
242266 { discarded , deps } = split_non_fulfilled_optional ( deps , kept , opts [ :from_umbrella ] )
243267
244268 new_breadths = Enum . map ( deps , & & 1 . app ) ++ breadths
245- all ( deps , acc , kept , breadths , new_breadths , discarded ++ optional , rest , lock , state )
269+ new_optional = discarded ++ optional
270+ all ( deps , app , acc , kept , breadths , new_breadths , new_optional , rest , lock , state )
246271 end
247272 end
248273
249- defp all ( [ ] , acc , kept , _upper , _current , optional , rest , lock , _state ) do
274+ defp all ( [ ] , _parent , acc , kept , _upper , _current , optional , rest , lock , _state ) do
250275 { acc , kept , optional , rest , lock }
251276 end
252277
@@ -264,7 +289,7 @@ defmodule Mix.Dep.Converger do
264289 # diverges is in the upper breadth, in those cases we
265290 # also check for the override option and mark the dependency
266291 # as overridden instead of diverged.
267- defp match_deps ( list , upper_breadths , % Mix.Dep { app: app } = dep , env_target ) do
292+ defp match_deps ( parent , list , upper_breadths , % Mix.Dep { app: app } = dep , env_target ) do
268293 case Enum . split_while ( list , & ( & 1 . app != app ) ) do
269294 { _ , [ ] } ->
270295 if Mix.Dep.Loader . skip? ( dep , env_target ) do
@@ -283,51 +308,84 @@ defmodule Mix.Dep.Converger do
283308 )
284309 end
285310
311+ override = Keyword . get ( other_opts , :override , false )
312+
286313 cond do
287- in_upper? && other_opts [ : override] ->
314+ in_upper? && override == true ->
288315 { :match , list }
289316
290317 not converge? ( other , dep ) ->
291- tag = if in_upper? , do: :overridden , else: :diverged
292- other = % { other | status: { tag , dep } }
293- { :match , pre ++ [ other | pos ] }
318+ if parent_overriden? ( override , parent ) do
319+ { :match , list }
320+ else
321+ tag = if in_upper? , do: :overridden , else: :diverged
322+ other = % { other | status: { tag , parent , dep } }
323+ { :match , pre ++ [ other | pos ] }
324+ end
294325
295326 vsn = req_mismatch ( other , dep ) ->
296- other = % { other | status: { :divergedreq , vsn , dep } }
297- { :match , pre ++ [ other | pos ] }
327+ if parent_overriden? ( override , parent ) do
328+ { :match , list }
329+ else
330+ other = % { other | status: { :divergedreq , vsn , parent , dep } }
331+ { :match , pre ++ [ other | pos ] }
332+ end
298333
299334 not in_upper? and Mix.Dep.Loader . skip? ( other , env_target ) and
300335 not Mix.Dep.Loader . skip? ( dep , env_target ) ->
301- dep =
302- dep
303- |> with_matching_only_and_targets ( other , in_upper? )
304- |> merge_manager ( other , in_upper? )
305-
306- { :replace , dep , pre ++ pos }
336+ dep
337+ |> merge_manager ( other , in_upper? )
338+ |> with_matching_only_and_targets ( other , in_upper? , override , parent , list , fn dep ->
339+ { :replace , dep , pre ++ pos }
340+ end )
307341
308342 true ->
309- other =
310- other
311- |> with_matching_only_and_targets ( dep , in_upper? )
312- |> merge_manager ( dep , in_upper? )
313-
314- { :match , pre ++ [ other | pos ] }
343+ other
344+ |> merge_manager ( dep , in_upper? )
345+ |> with_matching_only_and_targets ( dep , in_upper? , override , parent , list , fn other ->
346+ { :match , pre ++ [ other | pos ] }
347+ end )
315348 end
316349 end
317350 end
318351
319- defp with_matching_only_and_targets ( other , dep , in_upper? ) do
352+ defp parent_overriden? ( list , app ) when is_list ( list ) , do: app in list
353+ defp parent_overriden? ( _list , _app ) , do: false
354+
355+ defp with_matching_only_and_targets ( other , dep , in_upper? , override , parent , list , callback ) do
320356 % { opts: opts } = dep
321357
322358 if opts [ :optional ] do
323- other
359+ maybe_warn_uneeded_override ( dep , override , parent )
360+ callback . ( other )
324361 else
325- other
326- |> with_matching ( :only , dep , opts , in_upper? )
327- |> with_matching ( :targets , dep , opts , in_upper? )
362+ with { :ok , other } <- with_matching ( other , :only , dep , opts , in_upper? ) ,
363+ { :ok , other } <- with_matching ( other , :targets , dep , opts , in_upper? ) do
364+ maybe_warn_uneeded_override ( dep , override , parent )
365+ callback . ( other )
366+ else
367+ { :error , other } ->
368+ if parent_overriden? ( override , parent ) do
369+ { :match , list }
370+ else
371+ callback . ( other )
372+ end
373+ end
374+ end
375+ end
376+
377+ defp maybe_warn_uneeded_override ( dep , override , parent ) do
378+ if parent_overriden? ( override , parent ) do
379+ warn_uneeded_override ( dep , parent )
328380 end
329381 end
330382
383+ defp warn_uneeded_override ( dep , parent ) do
384+ Mix . shell ( ) . error (
385+ "Dependency #{ Mix.Dep . format_dep ( dep ) } no longer requires :override on #{ inspect ( parent ) } "
386+ )
387+ end
388+
331389 # When in_upper is true
332390 #
333391 # When a parent dependency specifies :only/:targets that is a
@@ -345,16 +403,16 @@ defmodule Mix.Dep.Converger do
345403 case Keyword . fetch ( opts , key ) do
346404 { :ok , value } ->
347405 case List . wrap ( value ) -- List . wrap ( other_value ) do
348- [ ] -> other
349- _ -> % { other | status: { :"diverged#{ key } " , dep } }
406+ [ ] -> { :ok , other }
407+ _ -> { :error , % { other | status: { :"diverged#{ key } " , dep } } }
350408 end
351409
352410 :error ->
353- % { other | status: { :"diverged#{ key } " , dep } }
411+ { :error , % { other | status: { :"diverged#{ key } " , dep } } }
354412 end
355413
356414 :error ->
357- other
415+ { :ok , other }
358416 end
359417 end
360418
@@ -369,9 +427,9 @@ defmodule Mix.Dep.Converger do
369427 value = Keyword . get ( opts , key )
370428
371429 if other_value && value do
372- put_in ( other . opts [ key ] , Enum . uniq ( List . wrap ( other_value ) ++ List . wrap ( value ) ) )
430+ { :ok , put_in ( other . opts [ key ] , Enum . uniq ( List . wrap ( other_value ) ++ List . wrap ( value ) ) ) }
373431 else
374- % { other | opts: Keyword . delete ( other_opts , key ) }
432+ { :ok , % { other | opts: Keyword . delete ( other_opts , key ) } }
375433 end
376434 end
377435
0 commit comments