compile.asn1.ex 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. defmodule Mix.Tasks.Compile.Asn1 do
  2. use Mix.Task.Compiler
  3. @recursive true
  4. @manifest_vsn 1
  5. @manifest "compile.asn1"
  6. # TODO: use manifest to track generated files?
  7. @impl true
  8. def manifests(), do: [manifest()]
  9. defp manifest(), do: Path.join(Mix.Project.manifest_path(), @manifest)
  10. @impl true
  11. def run(_args) do
  12. add_to_path_and_cache(:asn1)
  13. Mix.Project.get!()
  14. config = Mix.Project.config()
  15. app_root = File.cwd!()
  16. asn1_srcs = config[:asn1_srcs] || []
  17. manifest_data = read_manifest(manifest())
  18. manifest_modified_time = Mix.Utils.last_modified(manifest())
  19. Enum.each(asn1_srcs, &compile(&1, app_root, manifest_modified_time))
  20. write_manifest(manifest(), manifest_data)
  21. {:noop, []}
  22. end
  23. defp compile(src, app_root, manifest_modified_time) do
  24. %{
  25. src: src_path,
  26. compile_opts: compile_opts
  27. } = src
  28. src_path =
  29. app_root
  30. |> Path.join(src_path)
  31. |> Path.expand()
  32. if stale?(src_path, manifest_modified_time) do
  33. Mix.shell().info("compiling asn1 file: #{src_path}")
  34. :ok = :asn1ct.compile(to_charlist(src_path), compile_opts)
  35. else
  36. Mix.shell().info("file is up to date, not compiling: #{src_path}")
  37. end
  38. end
  39. defp stale?(file, manifest_modified_time) do
  40. with true <- File.exists?(file),
  41. false <- Mix.Utils.stale?([file], [manifest_modified_time]) do
  42. false
  43. else
  44. _ -> true
  45. end
  46. end
  47. defp read_manifest(file) do
  48. try do
  49. file |> File.read!() |> :erlang.binary_to_term()
  50. rescue
  51. _ -> %{}
  52. else
  53. {@manifest_vsn, data} when is_map(data) -> data
  54. _ -> %{}
  55. end
  56. end
  57. defp write_manifest(file, data) do
  58. Mix.shell().info("writing manifest #{file}")
  59. File.mkdir_p!(Path.dirname(file))
  60. File.write!(file, :erlang.term_to_binary({@manifest_vsn, data}))
  61. end
  62. def add_to_path_and_cache(lib_name) do
  63. :code.lib_dir()
  64. |> Path.join("#{lib_name}-*")
  65. |> Path.wildcard()
  66. |> hd()
  67. |> Path.join("ebin")
  68. |> to_charlist()
  69. |> :code.add_path(:cache)
  70. end
  71. end