diff --git a/init.lua b/init.lua index 0f89982..1e9ffb8 100644 --- a/init.lua +++ b/init.lua @@ -32,6 +32,49 @@ local M = {} +-- ===================================================================== +-- Engine binding probes (Slice 6) +-- +-- Slice 6 of the dep-fetcher plan wired engine.install_root() and +-- engine.config(key) as Lua-level bindings. We probe for them at +-- call-time (not load-time) so this lib continues to load under +-- engines that pre-date Slice 6 — the fallbacks (env var, hardcoded +-- URL) keep slice-5-compat with unmodified hosts. +-- ===================================================================== + +local function resolve_install_root(opts) + -- 1. explicit override + if opts and opts.install_root then return opts.install_root end + -- 2. Slice 6 engine binding + if type(engine) == "table" + and type(engine.install_root) == "function" then + local ok, root = pcall(engine.install_root) + if ok and type(root) == "string" and root ~= "" then + return root + end + end + -- 3. Slice 5 stop-gap: env var + return os.getenv("SPOREL_INSTALL_ROOT") +end + +local function resolve_gitea_base(opts) + -- 1. explicit override + if opts and opts.gitea_base then return opts.gitea_base end + -- 2. Slice 6 engine.config("gitea_base") (sourced from engine.json) + if type(engine) == "table" + and type(engine.config) == "function" then + local ok, val = pcall(engine.config, "gitea_base") + if ok and type(val) == "string" and val ~= "" then + return val + end + end + -- 3. Hardcoded slice-5 fallback + return "https://git.davoryn.de/sporel" +end + +M._resolve_install_root = resolve_install_root -- exposed for tests +M._resolve_gitea_base = resolve_gitea_base -- exposed for tests + -- ===================================================================== -- Pure-Lua JSON decoder (strict subset: object / array / string / -- number / true / false / null). Sufficient for manifest.lib / @@ -446,24 +489,28 @@ end -- ensure_for_module_at — full integrity check. -- module_manifest_path : absolute path to manifest.module -- opts: --- install_root : root of /libs/ — defaults to env --- SPOREL_INSTALL_ROOT (slice 6: engine.install_root()). +-- install_root : root of /libs/. Resolution chain (Slice 6): +-- 1. opts.install_root (explicit override) +-- 2. engine.install_root() if the binding is present +-- 3. SPOREL_INSTALL_ROOT env var (slice-5 stop-gap) -- check_only : skip per-lib git operations entirely -- (used by closure-shape unit tests). --- gitea_base : override default base URL. +-- gitea_base : override default base URL. Resolution chain: +-- 1. opts.gitea_base +-- 2. engine.config("gitea_base") if available +-- 3. hardcoded https://git.davoryn.de/sporel fallback function M.ensure_for_module_at(module_manifest_path, opts) opts = opts or {} - local install_root = opts.install_root - or os.getenv("SPOREL_INSTALL_ROOT") + local install_root = resolve_install_root(opts) if not install_root then return { ok = false, conflicts = {}, warnings = {}, errors = {{ lib_id = "", kind = "config", - message = "no install_root: pass opts.install_root or " .. - "set SPOREL_INSTALL_ROOT (slice 6 will add " .. - "engine.install_root() binding)", + message = "no install_root: pass opts.install_root, " .. + "set SPOREL_INSTALL_ROOT, or run under an engine " .. + "that provides engine.install_root()", }}, closure = {}, } @@ -507,8 +554,7 @@ function M.ensure_for_module_at(module_manifest_path, opts) end end - local gitea_base = opts.gitea_base - or "https://git.davoryn.de/sporel" + local gitea_base = resolve_gitea_base(opts) local warnings, errors = {}, {} run_state_check(unique, install_root, gitea_base, warnings, errors) @@ -523,17 +569,20 @@ function M.ensure_for_module_at(module_manifest_path, opts) end -- Convenience wrapper resolving the module-id via install layout. --- Slice 6 will replace SPOREL_INSTALL_ROOT with engine.install_root(). +-- Resolves install_root via the same Slice 6 chain as ensure_for_module_at: +-- explicit opts → engine.install_root() → SPOREL_INSTALL_ROOT env var. function M.ensure_for_module(module_id, opts) opts = opts or {} - local install_root = opts.install_root - or os.getenv("SPOREL_INSTALL_ROOT") + local install_root = resolve_install_root(opts) if not install_root then return { ok = false, conflicts = {}, warnings = {}, errors = {{ lib_id = "", kind = "config", - message = "no install_root for ensure_for_module", + message = "no install_root for ensure_for_module: " .. + "pass opts.install_root, set SPOREL_INSTALL_ROOT, " .. + "or run under an engine providing " .. + "engine.install_root()", }}, closure = {}, }