check-elixir-deps-discrepancies.exs 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. #!/usr/bin/env elixir
  2. # ensure we have a fresh rebar.lock
  3. case File.stat("rebar.lock") do
  4. {:ok, _} ->
  5. File.rm!("rebar.lock")
  6. _ ->
  7. :ok
  8. end
  9. {_, 0} =
  10. File.cwd!()
  11. |> Path.join("rebar3")
  12. |> System.cmd(["tree"], into: IO.stream())
  13. {:ok, props} = :file.consult("rebar.lock")
  14. {[{_, rebar_deps}], [props]} = Enum.split_with(props, &is_tuple/1)
  15. # dpendencies declared as package versions have a "secondary index"
  16. pkg_idx =
  17. props
  18. |> Keyword.fetch!(:pkg_hash)
  19. |> Map.new()
  20. rebar_deps =
  21. Map.new(rebar_deps, fn {name, ref, _} ->
  22. ref =
  23. case ref do
  24. {:pkg, _, _} ->
  25. pkg_idx
  26. |> Map.fetch!(name)
  27. |> String.downcase()
  28. {:git, _, {:ref, ref}} ->
  29. to_string(ref)
  30. end
  31. {name, ref}
  32. end)
  33. {mix_deps, []} = Code.eval_file("mix.lock")
  34. mix_deps =
  35. Map.new(mix_deps, fn {name, ref} ->
  36. ref =
  37. case ref do
  38. {:git, _, ref, _} ->
  39. ref
  40. {:hex, _, _, ref, _, _, _, _} ->
  41. ref
  42. end
  43. {to_string(name), ref}
  44. end)
  45. diffs =
  46. Enum.reduce(rebar_deps, %{}, fn {name, rebar_ref}, acc ->
  47. mix_ref = mix_deps[name]
  48. cond do
  49. mix_ref && mix_ref != rebar_ref ->
  50. Map.put(acc, name, {rebar_ref, mix_ref})
  51. is_nil(mix_ref) ->
  52. Map.put(acc, name, {rebar_ref, nil})
  53. :otherwise ->
  54. acc
  55. end
  56. end)
  57. if diffs == %{} do
  58. IO.puts(
  59. IO.ANSI.green() <>
  60. "* Mix and Rebar3 dependencies OK!" <>
  61. IO.ANSI.reset()
  62. )
  63. System.halt(0)
  64. else
  65. IO.puts(
  66. IO.ANSI.red() <>
  67. "* Discrepancies between Elixir and Rebar3 dependencies found!" <>
  68. IO.ANSI.reset()
  69. )
  70. Enum.each(diffs, fn {name, {rebar_ref, mix_ref}} ->
  71. IO.puts(
  72. IO.ANSI.red() <>
  73. " * #{name}\n" <>
  74. " * Rebar3 ref: #{rebar_ref}\n" <>
  75. " * Mix ref: #{mix_ref}\n" <>
  76. IO.ANSI.reset()
  77. )
  78. end)
  79. IO.puts(
  80. IO.ANSI.red() <>
  81. "Update `mix.exs` to match Rebar3's references (use `overwrite: true` if necessary) " <>
  82. "and/or run `mix deps.get` to update and try again" <>
  83. IO.ANSI.reset()
  84. )
  85. System.halt(1)
  86. end