Something went wrong. Try again.
Programmable CI/CD engine without Containers, written in Rust, built on top of Wasm and Nix fluentci.io
Something went wrong. Try again.
6.6 kB · 116 lines
Python
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117"""Canonical, statically declared ClojureScript guest imports (trusted FFI)."""import jsonfrom pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
def edn(value): if value is None: return "nil" if isinstance(value, dict): return "{" + " ".join(edn(k) + " " + edn(v) for k, v in value.items()) + "}" if isinstance(value, list): return "[" + " ".join(map(edn, value)) + "]" return json.dumps(value, ensure_ascii=False)
def type_of(spec): if "$ref" in spec: result = spec["$ref"].rsplit("/", 1)[1] elif spec.get("type") == "array": result = "(t/Vec " + type_of(spec["items"]) + ")" else: result = {"string": "t/Str", "boolean": "t/Bool", "integer": "t/Int", "buffer": "(t/Vec (t/HVec [t/Str t/Str]))"}[spec["type"]] return f"(t/Option {result})" if spec.get("nullable") else result
def generated(): schema = json.loads((ROOT / "schema/host.json").read_text()) lines = [';; Generated by scripts/xtp_codegen.py from schema/host.json. Do not edit.', '(ns ^:typed.clojure fluentci.pdk', ' "Complete low-level PDK. Calls mutate the legacy guest graph; prefer pure builders."', ' (:require [fluentci.bridge :as bridge]', ' #?(:cljs [fluentci.codec :as codec])', ' #?(:clj [typed.clojure :as t])))', '', '#?(:clj (do'] for name, spec in schema["components"]["schemas"].items(): if name == "Provider": variants = [f'(t/HMap :mandatory {{:{key} {type_of(dict(value, nullable=False))}}} :complete? true)' for key, value in spec["properties"].items()] value = '(t/U ' + ' '.join(variants) + ')' else: required = set(spec.get("required", [])) fields = lambda required_field: ' '.join( f':{key} {type_of(value)}' for key, value in spec["properties"].items() if (key in required) == required_field) value = f'(t/HMap :mandatory {{{fields(True)}}} :optional {{{fields(False)}}})' lines.append(f' (t/defalias {name} {value})') lines.extend(['))', '', '#?(:cljs (def ^:private schemas ' + edn(schema["components"]["schemas"]) + '))', '']) for name, function in schema["imports"].items(): public = name.replace('_', '-') + '!' argument, output = function.get('input'), function.get('output') parameters = 'value' if argument else '' signature = (type_of(argument) + ' ') if argument else '' lines.extend([f'#?(:clj (t/ann {public} [{signature}-> {type_of(output) if output else "nil"}]))', f'(defn {public} [{parameters}]', ' #?(:clj (throw (ex-info "Guest imports require Extism" {}))', ' :cljs']) if argument: lines.append(f' (do (codec/validate! schemas {edn(argument)} value)') encoded = 'nil' if not argument else ('value' if argument.get('contentType', '').startswith('text/plain') else '(bridge/json value)') call = f'(bridge/call! "{name}" {encoded} {"true" if output else "false"})' result = f'(codec/decode! schemas {edn(output)} {call})' if output and not output.get('contentType', '').startswith('text/plain') else call if not output: result = f'(do {call} nil)' lines.extend([' ' + result + (')' if argument else '') + '))', '']) yield ROOT / 'sdk/clojurescript/src/fluentci/pdk.cljc', '\n'.join(lines)
def sample(spec): if "$ref" in spec: name = spec["$ref"].rsplit("/", 1)[1] if name == "Provider": return {"Aws": {"aws_region": "test-region"}} component = schema["components"]["schemas"][name] return {key: sample(component["properties"][key]) for key in component.get("required", [])} if spec["type"] == "array": return [sample(spec["items"])] return {"string": "héllo 'quotes' 世界", "boolean": False, "integer": 32, "buffer": [["MODE", "release"]]}[spec["type"]]
def value_edn(value): if isinstance(value, dict): return '{' + ' '.join(':' + k + ' ' + value_edn(v) for k, v in value.items()) + '}' if isinstance(value, list): return '[' + ' '.join(map(value_edn, value)) + ']' return edn(value)
fixtures = [';; Generated schema-driven ABI fixtures. Not a guest implementation.', '(ns fluentci.pdk-contracts (:require [fluentci.pdk :as pdk]))', '(def calls ['] for name, function in schema["imports"].items(): arg, result = function.get('input'), function.get('output') fixtures.append(' [' + ' '.join([ 'pdk/' + name.replace('_', '-') + '!', edn(name), value_edn(sample(arg)) if arg else 'nil', value_edn(sample(result)) if result else 'nil', edn(bool(arg)), edn(bool(result)), edn(bool(arg and not arg.get('contentType', '').startswith('text/plain'))), edn(bool(result and not result.get('contentType', '').startswith('text/plain')))]) + ']') fixtures.append('])\n') yield ROOT / 'sdk/clojurescript/test/fluentci/pdk_contracts.cljs', '\n'.join(fixtures)
guide = ['# Canonical PDK coverage', '', 'Generated from `schema/host.json`. Every import has a public, statically declared', '`fluentci.pdk` function and a schema-driven ABI contract test. All functions are', 'effects. They directly mutate the legacy graph; use `fluentci.plugin` builders', 'or `fluentci.host` plans for reusable composition.', '', '| Host import | ClojureScript function | Input type | Output type |', '| --- | --- | --- | --- |'] for name, function in schema['imports'].items(): arg, result = function.get('input'), function.get('output') guide.append(f'| `{name}` | `{name.replace("_", "-")}!` | `{type_of(arg) if arg else "—"}` | `{type_of(result) if result else "nil"}` |') guide.extend(['', 'Object keys match the canonical wire schema (keywords, including `:Aws`).', '`set-envs!` takes a vector of `[name value]` pairs; `execute-plan!` takes', 'the protocol JSON string. Prefer `fluentci.host/run!` for a typed plan/result.', 'Unsigned range checks, JSON response validation and void/pointer ABI behavior', 'are enforced at the guest boundary.', '']) yield ROOT / 'sdk/clojurescript/API.md', '\n'.join(guide)