Fix Gleam stdlib runtime error in production

- Update gleam_compile task to copy all Gleam stdlib BEAM files
- Add release step to ensure Gleam BEAM files are included in releases
- Copy Gleam stdlib files from both priv/gleam and build directories

This fixes the "UndefinedFunctionError" for gleam@bit_array and other
Gleam stdlib modules in production by ensuring all required BEAM files
are included in the release.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Graham McIntire 2025-07-18 14:14:17 -05:00
parent 8cc2cf0a5e
commit fdcb0b6c5b
No known key found for this signature in database
2 changed files with 57 additions and 7 deletions

View file

@ -78,6 +78,23 @@ defmodule Mix.Tasks.GleamCompile do
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...")
@ -88,16 +105,23 @@ defmodule Mix.Tasks.GleamCompile do
if File.exists?(priv_gleam) do
File.mkdir_p!(ebin_dir)
# Look specifically for our Gleam module
beam_file = "aprsme@encoding.beam"
src = Path.join(priv_gleam, beam_file)
if File.exists?(src) do
# 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")
else
Mix.shell().error("Pre-compiled #{beam_file} not found in 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

26
mix.exs
View file

@ -20,6 +20,11 @@ defmodule Aprsme.MixProject do
plt_file:
{:no_warn,
"_build/dev/dialyxir_erlang-#{:erlang.system_info(:otp_release)}_elixir-#{System.version()}_deps-dev.plt"}
],
releases: [
aprsme: [
steps: [:assemble, &copy_gleam_files/1]
]
]
]
end
@ -142,4 +147,25 @@ defmodule Aprsme.MixProject do
# {:aprs, github: "aprsme/aprs", branch: "main"}
# end
end
# Copy Gleam BEAM files to the release
defp copy_gleam_files(release) do
app_dir = Path.join([release.path, "lib", "aprsme-#{release.version}", "ebin"])
File.mkdir_p!(app_dir)
# Copy from priv/gleam if available
priv_gleam = "priv/gleam"
if File.exists?(priv_gleam) do
priv_gleam
|> File.ls!()
|> Enum.filter(&String.ends_with?(&1, ".beam"))
|> Enum.each(fn beam_file ->
src = Path.join(priv_gleam, beam_file)
dest = Path.join(app_dir, beam_file)
File.copy!(src, dest)
end)
end
release
end
end