Skip to content

Commit decf951

Browse files
bougymanclaude
andauthored
feat(build): add mix burrito.dinein for local binary builds (#112)
## Summary - Adds `mix burrito.dinein` — a repo-level Mix task that auto-detects the current host platform and builds the Burrito-wrapped `lc` release for that single target only - Renames the output from `app/burrito_out/lc_<target>` to `app/burrito_out/lc` so it's immediately runnable without knowing the target suffix - Fails with an actionable error on unsupported platforms (macOS Intel, Linux ARM, etc.), listing the three supported targets ## What it does ``` mix burrito.dinein # builds for current host mix burrito.dinein --target linux_x86_64 # explicit override ``` Runs `MIX_ENV=prod BURRITO_TARGET=<detected> mix release lc --overwrite` inside `app/`, mirroring the pattern from `mix container.build`. After a successful build, renames the target-suffixed binary to plain `lc` (or `lc.exe` on Windows) in `app/burrito_out/`. ## Test plan - [x] `mix compile --warnings-as-errors` passes - [x] `mix test` passes — 8 tests (6 existing + 2 new) - Rejects extra positional arguments with usage message - `detect_target!/0` returns a known target name for the current host 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 5165c4e commit decf951

2 files changed

Lines changed: 138 additions & 0 deletions

File tree

lib/mix/tasks/burrito.dinein.ex

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
defmodule Mix.Tasks.Burrito.Dinein do
2+
@shortdoc "Builds a local Burrito lc binary for the current host platform"
3+
4+
@moduledoc """
5+
#{@shortdoc}.
6+
7+
mix burrito.dinein [--target TARGET]
8+
9+
Detects the current host platform, builds `app/`'s Burrito binary for that
10+
single target only (`MIX_ENV=prod BURRITO_TARGET=<target> mix release lc
11+
--overwrite`), then installs it as `app/burrito_out/lc` (dropping the
12+
target suffix) so it's immediately runnable as `./app/burrito_out/lc`.
13+
14+
Supported targets (auto-detected from the current host):
15+
- `macos_aarch64` — macOS Apple Silicon
16+
- `linux_x86_64` — Linux x86_64
17+
- `windows_x86_64` — Windows x86_64
18+
19+
Pass `--target TARGET` (`-t`) to override detection — useful for explicit
20+
cross-compilation when Zig can produce the target from this host.
21+
"""
22+
23+
use Mix.Task
24+
25+
alias RepoTasks.Shell
26+
27+
@supported_targets ~w[macos_aarch64 linux_x86_64 windows_x86_64]
28+
29+
@impl Mix.Task
30+
def run(argv) do
31+
{opts, args} =
32+
OptionParser.parse!(argv, strict: [target: :string], aliases: [t: :target])
33+
34+
unless args == [] do
35+
Mix.raise("Usage: mix burrito.dinein [--target TARGET]")
36+
end
37+
38+
target = opts[:target] || detect_target!()
39+
40+
Mix.shell().info("==> Fetching app/ deps")
41+
Shell.run!("mix", ["deps.get"], cd: "app")
42+
43+
Mix.shell().info("==> Building Burrito binary for #{target}")
44+
45+
Shell.run!(
46+
"mix",
47+
["release", "lc", "--overwrite"],
48+
cd: "app",
49+
env: [{"MIX_ENV", "prod"}, {"BURRITO_TARGET", target}]
50+
)
51+
52+
# Burrito names output lc_<target> (lc_<target>.exe on Windows).
53+
# Rename to plain lc (lc.exe) so it's immediately usable without knowing
54+
# the target suffix.
55+
ext = if target == "windows_x86_64", do: ".exe", else: ""
56+
src = Path.join("app/burrito_out", "lc_#{target}#{ext}")
57+
dst = Path.join("app/burrito_out", "lc#{ext}")
58+
59+
case File.rename(src, dst) do
60+
:ok ->
61+
Mix.shell().info("==> Built: #{dst}")
62+
63+
{:error, reason} ->
64+
Mix.raise("Failed to install #{src} as #{dst}: #{:file.format_error(reason)}")
65+
end
66+
67+
:ok
68+
end
69+
70+
@doc """
71+
Returns the Burrito target name matching the current host platform.
72+
73+
Raises `Mix.Error` with an actionable message on unsupported platforms.
74+
"""
75+
@spec detect_target!() :: String.t()
76+
def detect_target! do
77+
os = detect_os()
78+
cpu = detect_cpu()
79+
80+
case {os, cpu} do
81+
{:darwin, :aarch64} ->
82+
"macos_aarch64"
83+
84+
{:linux, :x86_64} ->
85+
"linux_x86_64"
86+
87+
{:windows, :x86_64} ->
88+
"windows_x86_64"
89+
90+
{os, cpu} ->
91+
Mix.raise(
92+
"Unsupported platform: #{os}/#{cpu}. " <>
93+
"Supported targets: #{Enum.join(@supported_targets, ", ")}"
94+
)
95+
end
96+
end
97+
98+
defp detect_os do
99+
case :os.type() do
100+
{:win32, _} -> :windows
101+
{:unix, :darwin} -> :darwin
102+
{:unix, :linux} -> :linux
103+
{:unix, other} -> other
104+
end
105+
end
106+
107+
defp detect_cpu do
108+
arch =
109+
:erlang.system_info(:system_architecture)
110+
|> to_string()
111+
|> String.downcase()
112+
|> String.split("-")
113+
|> List.first()
114+
115+
case arch do
116+
"x86_64" -> :x86_64
117+
"aarch64" -> :aarch64
118+
"arm64" -> :aarch64
119+
other -> other
120+
end
121+
end
122+
end
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
defmodule Mix.Tasks.Burrito.DineinTest do
2+
use ExUnit.Case, async: true
3+
4+
alias Mix.Tasks.Burrito.Dinein
5+
6+
test "rejects extra positional arguments" do
7+
assert_raise Mix.Error, "Usage: mix burrito.dinein [--target TARGET]", fn ->
8+
Dinein.run(["extra"])
9+
end
10+
end
11+
12+
test "detect_target! returns a known supported target for the current host" do
13+
target = Dinein.detect_target!()
14+
assert target in ~w[macos_aarch64 linux_x86_64 windows_x86_64]
15+
end
16+
end

0 commit comments

Comments
 (0)