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, best first: 1. **Pythonx** (embedded CPython, hermetic) — when the optional `:pythonx` dep is present, `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. `uv` on PATH — same hermetic properties via subprocess. 3. `python3` (>= 3.9) — stdlib legs directly; tree-sitter legs degrade with the toolchain's own honest hints. 4. None — a clear error naming the options. """ @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 = cond do Code.ensure_loaded?(Pythonx) -> run_pythonx(cli, args) 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 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) Pythonx.uv_init(@pythonx_project) {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} ) result |> Pythonx.decode() |> trunc() 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 needs a runtime. Any of: - add {:pythonx, "~> 0.4"} to your deps (recommended — hermetic: mix deps.get is the only prerequisite) - uv on PATH (https://docs.astral.sh/uv/) - python3 >= 3.9 on PATH (stdlib legs only, unless tree-sitter + tree-sitter-elixir are importable) """ end end