diff --git a/lib/mix/lib/mix/release.ex b/lib/mix/lib/mix/release.ex index 0e2659dfbfb..5e4fa474149 100644 --- a/lib/mix/lib/mix/release.ex +++ b/lib/mix/lib/mix/release.ex @@ -851,10 +851,13 @@ defmodule Mix.Release do source_file = Path.join(source, file) target_file = Path.join(target, file) - with true <- is_list(strip_options) and String.ends_with?(file, ".beam"), - {:ok, binary} <- strip_beam(File.read!(source_file), strip_options) do - File.write!(target_file, binary) - else + case Path.extname(file) do + ".beam" -> + process_beam_file(source_file, target_file, strip_options) + + ".app" -> + process_app_file(source_file, target_file) + _ -> # Use File.cp!/3 to preserve file mode for any executables stored # in the ebin directory. @@ -868,6 +871,25 @@ defmodule Mix.Release do end end + defp process_beam_file(source_file, target_file, strip_options) do + with true <- is_list(strip_options), + {:ok, binary} <- strip_beam(File.read!(source_file), strip_options) do + File.write!(target_file, binary) + else + _ -> File.cp!(source_file, target_file) + end + end + + defp process_app_file(source_file, target_file) do + with {:ok, [{:application, app, info}]} <- :file.consult(source_file) do + # Remove :config_mtime so that .app files are deterministic between builds + new_info = Keyword.delete(info, :config_mtime) + File.write!(target_file, :io_lib.format("~tp.~n", [{:application, app, new_info}])) + else + _ -> File.cp!(source_file, target_file) + end + end + @doc """ Strips a beam file for a release. diff --git a/lib/mix/test/mix/release_test.exs b/lib/mix/test/mix/release_test.exs index 28ccf9b3812..e42386450a9 100644 --- a/lib/mix/test/mix/release_test.exs +++ b/lib/mix/test/mix/release_test.exs @@ -686,9 +686,6 @@ defmodule Mix.ReleaseTest do test "copies and strips beams" do assert copy_ebin(release([]), @eex_ebin, tmp_path("eex_ebin")) - assert size!(Path.join(@eex_ebin, "eex.app")) == - size!(tmp_path("eex_ebin/eex.app")) - assert size!(Path.join(@eex_ebin, "Elixir.EEx.beam")) > size!(tmp_path("eex_ebin/Elixir.EEx.beam")) end @@ -696,9 +693,6 @@ defmodule Mix.ReleaseTest do test "copies without stripping beams" do assert copy_ebin(release(strip_beams: false), @eex_ebin, tmp_path("eex_ebin")) - assert size!(Path.join(@eex_ebin, "eex.app")) == - size!(tmp_path("eex_ebin/eex.app")) - assert size!(Path.join(@eex_ebin, "Elixir.EEx.beam")) == size!(tmp_path("eex_ebin/Elixir.EEx.beam")) end @@ -722,6 +716,13 @@ defmodule Mix.ReleaseTest do assert mode!(source_so_path) == mode!(tmp_path("mix_release/libtest_nif.so")) end + + test "removes config_mtime from app files" do + assert copy_ebin(release([]), @eex_ebin, tmp_path("eex_ebin")) + + {:ok, [{:application, :eex, info}]} = :file.consult(tmp_path("eex_ebin/eex.app")) + refute Keyword.get(info, :config_mtime) + end end describe "copy_app/2" do @@ -730,9 +731,6 @@ defmodule Mix.ReleaseTest do test "copies and strips beams" do assert copy_app(release(applications: [eex: :permanent]), :eex) - assert size!(Path.join(@eex_ebin, "eex.app")) == - size!(Path.join(@release_lib, "eex-#{@elixir_version}/ebin/eex.app")) - assert size!(Path.join(@eex_ebin, "Elixir.EEx.beam")) > size!(Path.join(@release_lib, "eex-#{@elixir_version}/ebin/Elixir.EEx.beam")) end @@ -740,9 +738,6 @@ defmodule Mix.ReleaseTest do test "copies without stripping beams" do assert copy_app(release(strip_beams: false, applications: [eex: :permanent]), :eex) - assert size!(Path.join(@eex_ebin, "eex.app")) == - size!(Path.join(@release_lib, "eex-#{@elixir_version}/ebin/eex.app")) - assert size!(Path.join(@eex_ebin, "Elixir.EEx.beam")) == size!(Path.join(@release_lib, "eex-#{@elixir_version}/ebin/Elixir.EEx.beam")) end @@ -760,6 +755,14 @@ defmodule Mix.ReleaseTest do refute File.exists?(Path.join(@release_lib, "runtime_tools-#{@runtime_tools_version}/ebin")) refute File.exists?(Path.join(@release_lib, "runtime_tools-#{@runtime_tools_version}/priv")) end + + test "removes config_mtime from app files" do + assert copy_app(release(strip_beams: false, applications: [eex: :permanent]), :eex) + + eex_app_path = Path.join(@release_lib, "eex-#{@elixir_version}/ebin/eex.app") + {:ok, [{:application, :eex, info}]} = :file.consult(eex_app_path) + refute Keyword.get(info, :config_mtime) + end end describe "strip_beam/1" do