defmodule Mix.Tasks.GleamCompile do @shortdoc "Compiles Gleam files and copies them to the correct location" @moduledoc false use Mix.Task def run(_args) do env = Mix.env() # Check if compile.gleam task exists task_exists = Code.ensure_loaded?(Mix.Tasks.Compile.Gleam) if task_exists do # First run the gleam compiler Mix.Task.run("compile.gleam") # Ensure output directory exists ebin_dir = "_build/#{env}/lib/aprsme/ebin" File.mkdir_p!(ebin_dir) # Copy beam files from Gleam build to Elixir build gleam_output = "build/#{env}/erlang/aprsme/_gleam_artefacts" if File.exists?(gleam_output) do gleam_output |> File.ls!() |> Enum.filter(&String.ends_with?(&1, ".beam")) |> Enum.each(fn beam_file -> src = Path.join(gleam_output, beam_file) dest = Path.join(ebin_dir, beam_file) File.copy!(src, dest) Mix.shell().info("Copied #{beam_file}") end) end else Mix.shell().info("Gleam compiler not available, compiling manually") # Compile Gleam files manually using gleam binary if available if System.find_executable("gleam") do Mix.shell().info("Found gleam binary, compiling...") {output, _exit_code} = System.cmd("gleam", ["build"], cd: File.cwd!()) Mix.shell().info(output) # Copy from gleam build to elixir build # Gleam always builds to dev directory regardless of MIX_ENV # The compiled files go to the project's ebin directory gleam_output = "build/dev/erlang/aprsme/ebin" ebin_dir = "_build/#{env}/lib/aprsme/ebin" File.mkdir_p!(ebin_dir) # First, check if compile.gleam already created the aprsme@encoding.beam dev_ebin = "_build/dev/lib/aprsme/ebin" if File.exists?(Path.join(dev_ebin, "aprsme@encoding.beam")) do Mix.shell().info("Found pre-compiled aprsme@encoding.beam") src = Path.join(dev_ebin, "aprsme@encoding.beam") dest = Path.join(ebin_dir, "aprsme@encoding.beam") File.copy!(src, dest) Mix.shell().info("Copied aprsme@encoding.beam to test build") end if File.exists?(gleam_output) do Mix.shell().info("Checking #{gleam_output} for beam files...") beam_files = gleam_output |> File.ls!() |> Enum.filter(&String.ends_with?(&1, ".beam")) Mix.shell().info("Found #{length(beam_files)} beam files") Enum.each(beam_files, fn beam_file -> src = Path.join(gleam_output, beam_file) dest = Path.join(ebin_dir, beam_file) File.copy!(src, dest) Mix.shell().info("Copied #{beam_file} to #{dest}") end) else Mix.shell().info("Gleam output directory #{gleam_output} does not exist") end # Also copy Gleam stdlib files gleam_stdlib_dir = "build/dev/erlang/gleam_stdlib/ebin" if File.exists?(gleam_stdlib_dir) do Mix.shell().info("Copying Gleam stdlib files...") gleam_stdlib_dir |> File.ls!() |> Enum.filter(&String.ends_with?(&1, ".beam")) |> Enum.each(fn beam_file -> src = Path.join(gleam_stdlib_dir, beam_file) dest = Path.join(ebin_dir, beam_file) File.copy!(src, dest) end) Mix.shell().info("Copied Gleam stdlib files") end else # Last resort: Check for pre-compiled BEAM files in priv/gleam Mix.shell().info("No Gleam compiler available, checking for pre-compiled BEAM files...") priv_gleam = "priv/gleam" ebin_dir = "_build/#{env}/lib/aprsme/ebin" if File.exists?(priv_gleam) do File.mkdir_p!(ebin_dir) # Copy all Gleam-related BEAM files priv_gleam |> File.ls!() |> Enum.filter(fn file -> String.ends_with?(file, ".beam") and (String.starts_with?(file, "gleam") or String.starts_with?(file, "aprsme@")) end) |> Enum.each(fn beam_file -> src = Path.join(priv_gleam, beam_file) dest = Path.join(ebin_dir, beam_file) File.copy!(src, dest) Mix.shell().info("Copied pre-compiled #{beam_file} from priv/gleam") end) # Check if we got the main module if not File.exists?(Path.join(ebin_dir, "aprsme@encoding.beam")) do Mix.shell().error("Pre-compiled aprsme@encoding.beam not found in priv/gleam") end else # Try to copy from dev build if available dev_ebin = "_build/dev/lib/aprsme/ebin" if File.exists?(dev_ebin) and env != :dev do File.mkdir_p!(ebin_dir) dev_ebin |> File.ls!() |> Enum.filter(&String.starts_with?(&1, "aprsme@")) |> Enum.each(fn beam_file -> src = Path.join(dev_ebin, beam_file) dest = Path.join(ebin_dir, beam_file) File.copy!(src, dest) Mix.shell().info("Copied #{beam_file} from dev build") end) else Mix.shell().error( "Unable to find Gleam compiled files. Please ensure Gleam code is compiled before deployment." ) end end end end :ok end end