Current section
Files
Jump to
Current section
Files
lib/dds.ex
defmodule Dds do
@moduledoc """
The dds toolchain, bundled. This module is a LOCATOR AND RUNNER,
nothing more — the instruments are the bundled Python (the same
bytes as the tagged toolchain repo), and all semantics live there.
Runtime resolution:
1. **Pythonx** (a hard dep — embedded CPython, hermetic):
`mix deps.get` is the ONLY prerequisite. Pythonx provisions a
standalone interpreter and the tree-sitter wheels itself (pinned
below), in-process, no system Python, no PATH. The mechanical
witness and evidence replay work out of the box.
2. Fallback, only when the host app already initialized pythonx
with its own interpreter AND that interpreter lacks our deps:
`uv` on PATH (same hermetic properties via subprocess), then
`python3` (stdlib legs, honest degradation), then a clear error.
"""
@pythonx_project """
[project]
name = "dds-runner"
version = "0.0.0"
requires-python = ">=3.10"
dependencies = ["tree-sitter", "tree-sitter-elixir"]
"""
@tree_deps ["tree-sitter", "tree-sitter-elixir"]
@doc "Run the bundled CLI with `args`; exits the VM with its exit code on failure."
def run(args) when is_list(args) do
cli = Path.join(:code.priv_dir(:dds), "toolchain/cli.py")
status =
case run_pythonx(cli, args) do
{:ok, s} -> s
:fallback -> run_path_tiers(cli, args)
end
if status != 0, do: exit({:shutdown, status})
:ok
end
defp run_pythonx(cli, args) do
# embedded CPython: pythonx downloads/caches a standalone build and
# the pinned deps; the toolchain runs in-process. SystemExit is the
# CLI's normal exit path — catch it and surface the code.
{:ok, _} = Application.ensure_all_started(:pythonx)
usable? =
try do
Pythonx.uv_init(@pythonx_project)
true
rescue
_ ->
# already initialized by the host app: usable only if ITS
# interpreter can serve the tree-sitter legs
{probe, _} =
Pythonx.eval(
"import importlib.util as u; bool(u.find_spec('tree_sitter'))",
%{}
)
Pythonx.decode(probe) == true
end
if not usable? do
IO.warn(
"pythonx was already initialized by the host app and its " <>
"interpreter lacks tree-sitter — falling back to uv/python3 on PATH"
)
throw(:fallback)
end
{result, _globals} =
Pythonx.eval(
"""
import runpy, sys
sys.argv = ["dds", *[a.decode() for a in args]]
_code = 0
try:
runpy.run_path(cli.decode(), run_name="__main__")
except SystemExit as e:
_code = int(e.code or 0)
_code
""",
%{"args" => args, "cli" => cli}
)
{:ok, result |> Pythonx.decode() |> trunc()}
catch
:fallback -> :fallback
end
defp run_path_tiers(cli, args) do
cond do
uv = System.find_executable("uv") -> run_cmd(uv, uv_args(cli, args))
py = System.find_executable("python3") -> run_cmd(py, [cli | args])
true -> raise_no_runtime()
end
end
defp uv_args(cli, args) do
["run", "--quiet"] ++ Enum.flat_map(@tree_deps, &["--with", &1]) ++ ["--", cli | args]
end
defp run_cmd(cmd, argv) do
{_, status} =
System.cmd(cmd, argv, into: IO.stream(:stdio, :line), stderr_to_stdout: true)
status
end
defp raise_no_runtime do
raise """
dds could not get a runtime: pythonx is unusable here (host-app
interpreter without tree-sitter) and neither uv nor python3 is on
PATH. Install uv (https://docs.astral.sh/uv/) or python3 >= 3.9.
"""
end
end