@voxgig/sdkgen 4.10.0 → 4.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/voxgig-sdkgen +1 -1
- package/package.json +1 -1
- package/project/.sdk/model/feature/secrets.aon +330 -0
- package/project/.sdk/model/target/c.aon +15 -2
- package/project/.sdk/model/target/cpp.aon +18 -0
- package/project/.sdk/model/target/lua.aon +17 -0
- package/project/.sdk/model/target/ocaml.aon +48 -5
- package/project/.sdk/model/target/zig.aon +30 -4
- package/project/.sdk/src/cmp/c/Config_c.ts +338 -1
- package/project/.sdk/src/cmp/c/Main_c.ts +57 -2
- package/project/.sdk/src/cmp/c/Package_c.ts +12 -2
- package/project/.sdk/src/cmp/cpp/Config_cpp.ts +324 -2
- package/project/.sdk/src/cmp/cpp/Gitignore_cpp.ts +2 -0
- package/project/.sdk/src/cmp/cpp/Main_cpp.ts +62 -4
- package/project/.sdk/src/cmp/cpp/Package_cpp.ts +10 -0
- package/project/.sdk/src/cmp/lua/Config_lua.ts +88 -0
- package/project/.sdk/src/cmp/lua/Gitignore_lua.ts +4 -0
- package/project/.sdk/src/cmp/lua/Main_lua.ts +93 -3
- package/project/.sdk/src/cmp/lua/Package_lua.ts +60 -0
- package/project/.sdk/src/cmp/lua/fragment/Main.fragment.lua +10 -0
- package/project/.sdk/src/cmp/ocaml/Config_ocaml.ts +183 -5
- package/project/.sdk/src/cmp/ocaml/Main_ocaml.ts +160 -3
- package/project/.sdk/src/cmp/ocaml/Package_ocaml.ts +25 -1
- package/project/.sdk/src/cmp/zig/Config_zig.ts +130 -9
- package/project/.sdk/src/cmp/zig/Main_zig.ts +208 -4
- package/project/.sdk/{tm/zig/build.zig → src/cmp/zig/fragment/Build.fragment.zig} +7 -0
- package/project/.sdk/src/cmp/zig/fragment/Main.fragment.zig +25 -0
- package/project/.sdk/{tm/zig/root.zig → src/cmp/zig/fragment/Root.fragment.zig} +9 -0
- package/project/.sdk/tm/c/Makefile +58 -9
- package/project/.sdk/tm/c/core/sdk.h +10 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/capability.c +133 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/capability.h +39 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/catalog.c +83 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/catalog.h +48 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/config.c +413 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/config.h +24 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/depend.c +264 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/depend.h +29 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/env.c +220 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/env.h +19 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/export.c +97 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/export.h +19 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/graph.c +237 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/graph.h +17 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/host.c +1494 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/host.h +135 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/order.c +288 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/order.h +18 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/point.c +141 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/point.h +80 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/ref.c +170 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/ref.h +52 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/resolve.c +98 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/resolve.h +18 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/types.c +150 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/types.h +104 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/value.c +649 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/value.h +135 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/version.c +151 -0
- package/project/.sdk/tm/c/feature/secrets/plugin/version.h +34 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/aws.c +281 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/azuresecrets.c +207 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/boru.c +164 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/clock.c +75 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/doppler.c +141 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/encode.c +144 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/gcpsecrets.c +177 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/hashicorp.c +239 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/httpjson.c +599 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/infisical.c +165 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/onepassword.c +194 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/proc.c +233 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/secretspec.c +125 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/sekretoplugins.h +125 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/sha256.c +270 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/sigv4.c +382 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/support.h +153 -0
- package/project/.sdk/tm/c/feature/secrets/plugins/tls.c +420 -0
- package/project/.sdk/tm/c/feature/secrets/sekreto/internal.h +86 -0
- package/project/.sdk/tm/c/feature/secrets/sekreto/json.c +721 -0
- package/project/.sdk/tm/c/feature/secrets/sekreto/providers.c +813 -0
- package/project/.sdk/tm/c/feature/secrets/sekreto/sekreto.c +944 -0
- package/project/.sdk/tm/c/feature/secrets/sekreto/sekreto.h +490 -0
- package/project/.sdk/tm/c/feature/secrets/sekreto/util.c +442 -0
- package/project/.sdk/tm/c/feature/secrets.c +797 -0
- package/project/.sdk/tm/c/feature/secrets.h +46 -0
- package/project/.sdk/tm/c/src/feature/secrets/.gitkeep +0 -0
- package/project/.sdk/tm/c/tests/feature/secrets/secrets_test.c +802 -0
- package/project/.sdk/tm/clojure/feature/secrets/sdk/feature/secrets.clj +38 -11
- package/project/.sdk/tm/clojure/test/sdk/test/feature/secrets.clj +40 -6
- package/project/.sdk/tm/cpp/Makefile +48 -4
- package/project/.sdk/tm/cpp/feature/secrets/plugin/capability.cpp +121 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/capability.hpp +41 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/catalog.cpp +60 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/catalog.hpp +66 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/config.cpp +376 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/config.hpp +29 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/depend.cpp +230 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/depend.hpp +31 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/env.cpp +205 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/env.hpp +25 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/export.cpp +84 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/export.hpp +24 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/graph.cpp +222 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/graph.hpp +21 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/host.cpp +1200 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/host.hpp +250 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/order.cpp +250 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/order.hpp +22 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/point.cpp +110 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/point.hpp +79 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/ref.cpp +136 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/ref.hpp +60 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/resolve.cpp +82 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/resolve.hpp +25 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/types.cpp +90 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/types.hpp +65 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/value.cpp +491 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/value.hpp +120 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/version.cpp +143 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugin/version.hpp +36 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Aws.cpp +248 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Aws.hpp +30 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Azuresecrets.cpp +149 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Azuresecrets.hpp +23 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Boru.cpp +117 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Boru.hpp +27 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Crypto.cpp +180 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Crypto.hpp +52 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Doppler.cpp +87 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Doppler.hpp +23 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Gcpsecrets.cpp +121 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Gcpsecrets.hpp +23 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Hashicorp.cpp +153 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Hashicorp.hpp +23 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Httpjson.cpp +666 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Httpjson.hpp +160 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Infisical.cpp +123 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Infisical.hpp +23 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Onepassword.cpp +125 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Onepassword.hpp +23 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Proc.cpp +223 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Proc.hpp +47 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Secretspec.cpp +104 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Secretspec.hpp +27 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Sigv4.cpp +242 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Sigv4.hpp +58 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Tls.cpp +260 -0
- package/project/.sdk/tm/cpp/feature/secrets/plugins/Tls.hpp +47 -0
- package/project/.sdk/tm/cpp/feature/secrets/sekreto/Json.cpp +476 -0
- package/project/.sdk/tm/cpp/feature/secrets/sekreto/Json.hpp +89 -0
- package/project/.sdk/tm/cpp/feature/secrets/sekreto/Provider.cpp +312 -0
- package/project/.sdk/tm/cpp/feature/secrets/sekreto/Provider.hpp +263 -0
- package/project/.sdk/tm/cpp/feature/secrets/sekreto/Providers.cpp +354 -0
- package/project/.sdk/tm/cpp/feature/secrets/sekreto/Providers.hpp +111 -0
- package/project/.sdk/tm/cpp/feature/secrets/sekreto/Sekreto.cpp +613 -0
- package/project/.sdk/tm/cpp/feature/secrets/sekreto/Sekreto.hpp +227 -0
- package/project/.sdk/tm/cpp/feature/secrets.hpp +745 -0
- package/project/.sdk/tm/cpp/src/feature/secrets/.gitkeep +0 -0
- package/project/.sdk/tm/cpp/test/feature/secrets/secrets_test.cpp +808 -0
- package/project/.sdk/tm/csharp/feature/SecretsFeature.cs +34 -8
- package/project/.sdk/tm/csharp/test/feature/secrets/SecretsFeatureTest.cs +85 -0
- package/project/.sdk/tm/elixir/lib/projectname/feature/secrets.ex +17 -2
- package/project/.sdk/tm/elixir/test/feature/secrets/secrets_test.exs +41 -0
- package/project/.sdk/tm/go/feature/secrets_feature.go +32 -10
- package/project/.sdk/tm/go/test/feature/secrets/secrets_feature_test.go +116 -0
- package/project/.sdk/tm/java/feature/SecretsFeature.java +33 -8
- package/project/.sdk/tm/java/test/feature/secrets/SecretsFeatureTest.java +64 -0
- package/project/.sdk/tm/js/src/feature/secrets/SecretsFeature.js +34 -11
- package/project/.sdk/tm/js/test/feature/secrets/Secrets.test.js +73 -0
- package/project/.sdk/tm/kotlin/feature/SecretsFeature.kt +32 -7
- package/project/.sdk/tm/kotlin/test/feature/secrets/SecretsTest.kt +69 -0
- package/project/.sdk/tm/lua/Makefile +15 -4
- package/project/.sdk/tm/lua/feature/secrets/native/sekretonet.c +806 -0
- package/project/.sdk/tm/lua/feature/secrets/plugin/capability.lua +135 -0
- package/project/.sdk/tm/lua/feature/secrets/plugin/catalog.lua +63 -0
- package/project/.sdk/tm/lua/feature/secrets/plugin/config.lua +361 -0
- package/project/.sdk/tm/lua/feature/secrets/plugin/depend.lua +232 -0
- package/project/.sdk/tm/lua/feature/secrets/plugin/env.lua +168 -0
- package/project/.sdk/tm/lua/feature/secrets/plugin/export.lua +66 -0
- package/project/.sdk/tm/lua/feature/secrets/plugin/graph.lua +194 -0
- package/project/.sdk/tm/lua/feature/secrets/plugin/host.lua +1190 -0
- package/project/.sdk/tm/lua/feature/secrets/plugin/json.lua +169 -0
- package/project/.sdk/tm/lua/feature/secrets/plugin/order.lua +207 -0
- package/project/.sdk/tm/lua/feature/secrets/plugin/point.lua +106 -0
- package/project/.sdk/tm/lua/feature/secrets/plugin/ref.lua +115 -0
- package/project/.sdk/tm/lua/feature/secrets/plugin/resolve.lua +78 -0
- package/project/.sdk/tm/lua/feature/secrets/plugin/types.lua +275 -0
- package/project/.sdk/tm/lua/feature/secrets/plugin/version.lua +131 -0
- package/project/.sdk/tm/lua/feature/secrets/plugin.lua +76 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/addr.lua +124 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/err.lua +47 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/name.lua +315 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/aws.lua +228 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/azuresecrets.lua +137 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/boru.lua +124 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/crypto.lua +212 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/doppler.lua +89 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/gcpsecrets.lua +129 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/hashicorp.lua +154 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/httpjson.lua +248 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/infisical.lua +113 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/json.lua +449 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/net.lua +198 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/onepassword.lua +126 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/secretspec.lua +93 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/sigv4.lua +269 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/plugins/support.lua +146 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto/providers.lua +346 -0
- package/project/.sdk/tm/lua/feature/secrets/sekreto.lua +479 -0
- package/project/.sdk/tm/lua/feature/secrets_feature.lua +690 -0
- package/project/.sdk/tm/lua/src/feature/secrets/.gitkeep +0 -0
- package/project/.sdk/tm/lua/test/extend_test.lua +105 -0
- package/project/.sdk/tm/lua/test/feature/secrets/secrets_feature_test.lua +862 -0
- package/project/.sdk/tm/ocaml/Makefile +52 -8
- package/project/.sdk/tm/ocaml/feature/secrets/plugin/capability.ml +106 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugin/catalog.ml +43 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugin/config.ml +349 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugin/defs.ml +143 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugin/depend.ml +217 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugin/env.ml +197 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugin/export.ml +89 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugin/graph.ml +227 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugin/host.ml +1112 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugin/order.ml +202 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugin/point.ml +138 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugin/ref.ml +126 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugin/resolve.ml +62 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugin/types.ml +97 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugin/value.ml +387 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugin/version.ml +139 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugins/aws.ml +171 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugins/azuresecrets.ml +116 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugins/boru.ml +95 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugins/crypto.ml +149 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugins/doppler.ml +61 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugins/gcpsecrets.ml +93 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugins/hashicorp.ml +120 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugins/http.ml +421 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugins/httpjson.ml +66 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugins/infisical.ml +85 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugins/onepassword.ml +112 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugins/runcmd.ml +97 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugins/secretspec.ml +68 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugins/sigv4.ml +259 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugins/tls.ml +44 -0
- package/project/.sdk/tm/ocaml/feature/secrets/plugins/tls_stubs.c +358 -0
- package/project/.sdk/tm/ocaml/feature/secrets/sekreto/json.ml +376 -0
- package/project/.sdk/tm/ocaml/feature/secrets/sekreto/provider.ml +647 -0
- package/project/.sdk/tm/ocaml/feature/secrets/sekreto/secret.ml +299 -0
- package/project/.sdk/tm/ocaml/feature/secrets/sekreto/sekreto.ml +347 -0
- package/project/.sdk/tm/ocaml/feature/secrets_feature.ml +453 -0
- package/project/.sdk/tm/ocaml/src/feature/secrets/.gitkeep +0 -0
- package/project/.sdk/tm/ocaml/test/feature/secrets/t_secrets.ml +670 -0
- package/project/.sdk/tm/perl/feature/secrets_feature.pm +33 -12
- package/project/.sdk/tm/perl/t/feature/secrets/secrets.t +47 -0
- package/project/.sdk/tm/php/feature/SecretsFeature.php +30 -6
- package/project/.sdk/tm/php/test/feature/secrets/SecretsTest.php +98 -0
- package/project/.sdk/tm/py/pkg/feature/secrets_feature.py +28 -6
- package/project/.sdk/tm/py/test/feature/secrets/test_secrets.py +114 -0
- package/project/.sdk/tm/rb/feature/secrets_feature.rb +28 -6
- package/project/.sdk/tm/rb/test/feature/secrets/secrets_feature_test.rb +93 -0
- package/project/.sdk/tm/rust/feature/secrets.rs +33 -10
- package/project/.sdk/tm/rust/tests/feature/secrets/main.rs +96 -0
- package/project/.sdk/tm/scala/feature/SecretsFeature.scala +29 -7
- package/project/.sdk/tm/scala/sdktest/feature/secrets/SecretsTestMain.scala +71 -0
- package/project/.sdk/tm/ts/src/feature/secrets/SecretsFeature.ts +35 -12
- package/project/.sdk/tm/ts/test/feature/secrets/Secrets.test.ts +73 -0
- package/project/.sdk/tm/zig/feature/secrets/plugin/capability.zig +137 -0
- package/project/.sdk/tm/zig/feature/secrets/plugin/catalog.zig +90 -0
- package/project/.sdk/tm/zig/feature/secrets/plugin/config.zig +346 -0
- package/project/.sdk/tm/zig/feature/secrets/plugin/depend.zig +244 -0
- package/project/.sdk/tm/zig/feature/secrets/plugin/env.zig +201 -0
- package/project/.sdk/tm/zig/feature/secrets/plugin/export.zig +83 -0
- package/project/.sdk/tm/zig/feature/secrets/plugin/graph.zig +212 -0
- package/project/.sdk/tm/zig/feature/secrets/plugin/host.zig +1224 -0
- package/project/.sdk/tm/zig/feature/secrets/plugin/inst.zig +126 -0
- package/project/.sdk/tm/zig/feature/secrets/plugin/order.zig +228 -0
- package/project/.sdk/tm/zig/feature/secrets/plugin/plugin.zig +34 -0
- package/project/.sdk/tm/zig/feature/secrets/plugin/point.zig +166 -0
- package/project/.sdk/tm/zig/feature/secrets/plugin/ref.zig +147 -0
- package/project/.sdk/tm/zig/feature/secrets/plugin/resolve.zig +74 -0
- package/project/.sdk/tm/zig/feature/secrets/plugin/types.zig +140 -0
- package/project/.sdk/tm/zig/feature/secrets/plugin/value.zig +662 -0
- package/project/.sdk/tm/zig/feature/secrets/plugin/version.zig +139 -0
- package/project/.sdk/tm/zig/feature/secrets/plugins/aws.zig +294 -0
- package/project/.sdk/tm/zig/feature/secrets/plugins/azuresecrets.zig +222 -0
- package/project/.sdk/tm/zig/feature/secrets/plugins/boru.zig +188 -0
- package/project/.sdk/tm/zig/feature/secrets/plugins/doppler.zig +135 -0
- package/project/.sdk/tm/zig/feature/secrets/plugins/gcpsecrets.zig +170 -0
- package/project/.sdk/tm/zig/feature/secrets/plugins/hashicorp.zig +242 -0
- package/project/.sdk/tm/zig/feature/secrets/plugins/httpjson.zig +535 -0
- package/project/.sdk/tm/zig/feature/secrets/plugins/infisical.zig +167 -0
- package/project/.sdk/tm/zig/feature/secrets/plugins/onepassword.zig +202 -0
- package/project/.sdk/tm/zig/feature/secrets/plugins/secretspec.zig +160 -0
- package/project/.sdk/tm/zig/feature/secrets/plugins/sigv4.zig +336 -0
- package/project/.sdk/tm/zig/feature/secrets/sekreto/addr.zig +148 -0
- package/project/.sdk/tm/zig/feature/secrets/sekreto/builtins.zig +259 -0
- package/project/.sdk/tm/zig/feature/secrets/sekreto/provider.zig +440 -0
- package/project/.sdk/tm/zig/feature/secrets/sekreto/sekreto.zig +944 -0
- package/project/.sdk/tm/zig/feature/secrets.zig +854 -0
- package/project/.sdk/tm/zig/src/feature/secrets/.gitkeep +0 -0
- package/project/.sdk/tm/zig/test/feature/secrets/secrets_test.zig +891 -0
- package/project/sdkgen-package.json +1 -1
|
@@ -0,0 +1,1224 @@
|
|
|
1
|
+
// VENDORED: @voxgig/plugin sdk-20260908-1556-0 (zig/src/host.zig)
|
|
2
|
+
// Source: https://github.com/voxgig/plugin @ 48392f5e2b6d1434ee9b1a4a9a11f4480aaeb46a [tag: sdk-20260908-1556-0]
|
|
3
|
+
// License: MIT (c) voxgig - see repository LICENSE. Do not edit: resync from upstream.
|
|
4
|
+
//! The host: the lifecycle state machine (§5), extension points (§6),
|
|
5
|
+
//! and resource capture (§8).
|
|
6
|
+
//!
|
|
7
|
+
//! TWO RULES SHAPE EVERY FUNCTION HERE.
|
|
8
|
+
//!
|
|
9
|
+
//! Transitions are SEQUENTIAL (§5.2). One at a time, in call order,
|
|
10
|
+
//! never interleaved; a transition triggered from inside a lifecycle
|
|
11
|
+
//! callback is `plugin_reentrant`. A hard rule, because it is the only
|
|
12
|
+
//! way the semantics can be identical in Go, in Ruby and in
|
|
13
|
+
//! single-threaded JavaScript — and in zig, which has no event loop to
|
|
14
|
+
//! hide behind.
|
|
15
|
+
//!
|
|
16
|
+
//! Reconciliation is EAGER (§18's portability budget). A transition
|
|
17
|
+
//! settles by running the state machine to a fixed point, not by
|
|
18
|
+
//! suspending on a promise.
|
|
19
|
+
|
|
20
|
+
const std = @import("std");
|
|
21
|
+
const v = @import("value.zig");
|
|
22
|
+
const t = @import("types.zig");
|
|
23
|
+
const cap = @import("capability.zig");
|
|
24
|
+
const catalog = @import("catalog.zig");
|
|
25
|
+
const cfg = @import("config.zig");
|
|
26
|
+
const dep = @import("depend.zig");
|
|
27
|
+
const exp = @import("export.zig");
|
|
28
|
+
const ord = @import("order.zig");
|
|
29
|
+
const point = @import("point.zig");
|
|
30
|
+
const ref = @import("ref.zig");
|
|
31
|
+
const model = @import("inst.zig");
|
|
32
|
+
|
|
33
|
+
pub const Inst = model.Inst;
|
|
34
|
+
pub const Host = model.Host;
|
|
35
|
+
pub const HostOptions = model.HostOptions;
|
|
36
|
+
pub const DeclareSpec = model.DeclareSpec;
|
|
37
|
+
pub const ScopeEntry = model.ScopeEntry;
|
|
38
|
+
pub const BaseFn = model.BaseFn;
|
|
39
|
+
pub const Definition = catalog.Definition;
|
|
40
|
+
|
|
41
|
+
// ---------------------------------------------------------------------
|
|
42
|
+
// construction and registry helpers
|
|
43
|
+
// ---------------------------------------------------------------------
|
|
44
|
+
|
|
45
|
+
pub fn makehost(o: HostOptions) *Host {
|
|
46
|
+
const h = v.arena().create(Host) catch @panic("oom");
|
|
47
|
+
h.* = .{
|
|
48
|
+
.catalog = o.catalog orelse catalog.makecatalog(),
|
|
49
|
+
.reserved = o.reserved,
|
|
50
|
+
.keys = o.keys,
|
|
51
|
+
.defaults = o.defaults,
|
|
52
|
+
.profile = o.profile,
|
|
53
|
+
.points = if (v.isMap(o.points)) o.points.? else v.vmap(),
|
|
54
|
+
.bases = o.bases,
|
|
55
|
+
.dependency = if (o.dependency.len == 0) "restart" else o.dependency,
|
|
56
|
+
.instances = v.List(*Inst).init(v.arena()),
|
|
57
|
+
.log = v.vlist(),
|
|
58
|
+
.events = v.vlist(),
|
|
59
|
+
};
|
|
60
|
+
return h;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
pub fn define(h: *Host, d: *Definition) t.Err!void {
|
|
64
|
+
return h.catalog.add(d);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
fn find(h: *Host, r: []const u8) ?*Inst {
|
|
68
|
+
for (h.instances.items) |e| {
|
|
69
|
+
if (std.mem.eql(u8, e.ref, r)) return e;
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
fn lessStr(_: void, a: []const u8, b: []const u8) bool {
|
|
75
|
+
return std.mem.order(u8, a, b) == .lt;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/// Every instance ref, SORTED — the deterministic walk §4 rule 4
|
|
79
|
+
/// requires in a language whose containers have no inherent order.
|
|
80
|
+
fn sortedrefs(h: *Host) [][]const u8 {
|
|
81
|
+
const out = v.arena().alloc([]const u8, h.instances.items.len) catch @panic("oom");
|
|
82
|
+
for (h.instances.items, 0..) |e, i| out[i] = e.ref;
|
|
83
|
+
std.mem.sort([]const u8, out, {}, lessStr);
|
|
84
|
+
return out;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// ---------------------------------------------------------------------
|
|
88
|
+
// observation
|
|
89
|
+
// ---------------------------------------------------------------------
|
|
90
|
+
|
|
91
|
+
pub fn list(h: *Host) *v.Value {
|
|
92
|
+
const out = v.vmap();
|
|
93
|
+
for (sortedrefs(h)) |r| {
|
|
94
|
+
if (find(h, r)) |e| v.set(out, r, v.vstr(e.status));
|
|
95
|
+
}
|
|
96
|
+
return out;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/// The VALIDATING canonicalizer, not the forgiving one: a lookup with a
|
|
100
|
+
/// malformed ref is `plugin_bad_name`, not a miss
|
|
101
|
+
/// (`declare/lookup#malformed`). Rust and swift both wrote this with
|
|
102
|
+
/// `canon` and failed that entry.
|
|
103
|
+
pub fn instance(h: *Host, r: []const u8) t.Err!?*Inst {
|
|
104
|
+
return find(h, try ref.canonrefs(r));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
pub fn observable(h: *Host, result: ?*v.Value, hasresult: bool) *v.Value {
|
|
108
|
+
const out = v.vmap();
|
|
109
|
+
v.set(out, "status", list(h));
|
|
110
|
+
v.set(out, "open", v.vnum(h.open));
|
|
111
|
+
const lg = v.vlist();
|
|
112
|
+
for (v.items(h.log)) |x| v.push(lg, x);
|
|
113
|
+
v.set(out, "log", lg);
|
|
114
|
+
v.set(out, "result", if (!hasresult or result == null) v.vnull() else result);
|
|
115
|
+
return out;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/// A COPY, not the live list: the canonical is `trace: () => events.slice()`, and `observable` already copies the log. Returning the live list lets a caller append to or delete from the host's own event record — application observation code fabricating or erasing lifecycle history.
|
|
119
|
+
pub fn trace(h: *Host) *v.Value {
|
|
120
|
+
const out = v.vlist();
|
|
121
|
+
for (v.items(h.events)) |x| v.push(out, x);
|
|
122
|
+
return out;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
pub fn instname(e: *Inst) []const u8 {
|
|
126
|
+
return ref.refname(e.ref);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
pub fn insttag(e: *Inst) []const u8 {
|
|
130
|
+
const cut = std.mem.indexOfScalar(u8, e.ref, '$') orelse return "";
|
|
131
|
+
return e.ref[cut + 1 ..];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// ---------------------------------------------------------------------
|
|
135
|
+
// guards
|
|
136
|
+
// ---------------------------------------------------------------------
|
|
137
|
+
|
|
138
|
+
fn guard(h: *Host) t.Err!void {
|
|
139
|
+
if (h.intransition) {
|
|
140
|
+
return t.fail("plugin_reentrant", "transition attempted from inside a lifecycle callback", null);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
fn need(h: *Host, r0: []const u8) t.Err!*Inst {
|
|
145
|
+
const r = try ref.canonrefs(r0);
|
|
146
|
+
return find(h, r) orelse
|
|
147
|
+
t.fail("plugin_not_loaded", v.print("no such instance: {s}", .{r}), t.details1("ref", v.vstr(r)));
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
fn checkreserved(h: *Host, r: []const u8) t.Err!void {
|
|
151
|
+
if (!v.isList(h.reserved) or v.len(h.reserved) == 0) return;
|
|
152
|
+
const name = ref.refname(r);
|
|
153
|
+
for (v.items(h.reserved)) |x| {
|
|
154
|
+
if (v.isStr(x) and std.mem.eql(u8, v.asStr(x), name)) {
|
|
155
|
+
return t.fail("plugin_ref_reserved", v.print("ref is reserved by the host: {s}", .{r}), t.details1("ref", v.vstr(r)));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// ---------------------------------------------------------------------
|
|
161
|
+
// scope
|
|
162
|
+
// ---------------------------------------------------------------------
|
|
163
|
+
|
|
164
|
+
fn pushscope(e: *Inst, f: ?model.ReleaseFn, ctx: ?*anyopaque, counts: bool) *ScopeEntry {
|
|
165
|
+
const s = v.arena().create(ScopeEntry) catch @panic("oom");
|
|
166
|
+
s.* = .{ .fn_ = f, .ctx = ctx, .done = false, .counts = counts };
|
|
167
|
+
e.scope.append(s) catch @panic("oom");
|
|
168
|
+
return s;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/// A selection belongs to ONE activation (§11.4). Leaving `live` by any
|
|
172
|
+
/// door drops it, so the next activation ranks afresh — keeping it would
|
|
173
|
+
/// make a consumer prefer a provider it never actually ran against.
|
|
174
|
+
///
|
|
175
|
+
/// Answers the errors the scope raised. §8.3: "A failing release does
|
|
176
|
+
/// not stop the rest. Every entry runs, in reverse order, whatever any
|
|
177
|
+
/// of them does; the errors are collected and raised as one
|
|
178
|
+
/// `plugin_release_failed`."
|
|
179
|
+
///
|
|
180
|
+
/// A RELEASE CANNOT FAIL IN ZIG'S TYPE SYSTEM: `ReleaseFn` returns void,
|
|
181
|
+
/// because a release that could return an error would make every unwind
|
|
182
|
+
/// site fallible for a failure the contract says must not stop the rest.
|
|
183
|
+
/// The probe that must raise does so through the host's own error slot,
|
|
184
|
+
/// which `releasefailed` reads.
|
|
185
|
+
fn unwind(h: *Host, e: *Inst) *v.Value {
|
|
186
|
+
e.selected = v.vmap();
|
|
187
|
+
const errors = v.vlist();
|
|
188
|
+
var k = e.scope.items.len;
|
|
189
|
+
while (k > 0) {
|
|
190
|
+
k -= 1;
|
|
191
|
+
const s = e.scope.items[k];
|
|
192
|
+
if (s.done) continue;
|
|
193
|
+
s.done = true;
|
|
194
|
+
if (s.counts) h.open -= 1;
|
|
195
|
+
if (s.fn_) |f| {
|
|
196
|
+
release_error = null;
|
|
197
|
+
f(s.ctx);
|
|
198
|
+
if (release_error) |msg| v.push(errors, v.vstr(msg));
|
|
199
|
+
release_error = null;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
e.scope.clearRetainingCapacity();
|
|
203
|
+
return errors;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/// The one channel a release has to report a failure, since it cannot
|
|
207
|
+
/// return one. Set by a release callback, read by `unwind`.
|
|
208
|
+
pub var release_error: ?[]const u8 = null;
|
|
209
|
+
|
|
210
|
+
/// §8.3: "A failed release ends the instance in `failed`, exactly as a
|
|
211
|
+
/// failed callback does (§5.2) — a release that raised may have leaked,
|
|
212
|
+
/// and an instance that may be holding resources it cannot account for
|
|
213
|
+
/// must not be reactivated."
|
|
214
|
+
fn releasecheck(e: *Inst, errors: *v.Value) t.Err!void {
|
|
215
|
+
if (v.len(errors) == 0) return;
|
|
216
|
+
e.status = "failed";
|
|
217
|
+
var why = v.List(u8).init(v.arena());
|
|
218
|
+
for (v.items(errors), 0..) |x, i| {
|
|
219
|
+
if (i > 0) why.appendSlice("; ") catch @panic("oom");
|
|
220
|
+
why.appendSlice(v.asStr(x)) catch @panic("oom");
|
|
221
|
+
}
|
|
222
|
+
const d = v.vmap();
|
|
223
|
+
v.set(d, "ref", v.vstr(e.ref));
|
|
224
|
+
v.set(d, "cause", errors);
|
|
225
|
+
return t.fail("plugin_release_failed", v.print("release failed for {s}: {s}", .{ e.ref, why.items }), d);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// ---------------------------------------------------------------------
|
|
229
|
+
// the instance api
|
|
230
|
+
// ---------------------------------------------------------------------
|
|
231
|
+
|
|
232
|
+
pub fn acquire(e: *Inst) t.Err!*ScopeEntry {
|
|
233
|
+
// §8.1: resources are "acquired during `activate` — the scope's
|
|
234
|
+
// actual job".
|
|
235
|
+
if (!std.mem.eql(u8, e.owner.phase, "activate")) {
|
|
236
|
+
return t.fail("plugin_release_scope", "acquire called outside activate", null);
|
|
237
|
+
}
|
|
238
|
+
const s = pushscope(e, null, null, true);
|
|
239
|
+
e.owner.open += 1;
|
|
240
|
+
return s;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/// Hand a resource back before teardown. Idempotent, and the scope keeps
|
|
244
|
+
/// the entry: unwinding it again must be a no-op, or releasing early
|
|
245
|
+
/// would make teardown wrong.
|
|
246
|
+
pub fn giveback(e: *Inst, s: *ScopeEntry) void {
|
|
247
|
+
if (s.done) return;
|
|
248
|
+
s.done = true;
|
|
249
|
+
if (s.counts) e.owner.open -= 1;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
pub fn release(e: *Inst, f: ?model.ReleaseFn, ctx: ?*anyopaque) t.Err!void {
|
|
253
|
+
// §8.3: "`inst.release` outside `activate` is
|
|
254
|
+
// `plugin_release_scope`". Being in a transition is true in `define`
|
|
255
|
+
// too, and a scope entry registered there is never unwound —
|
|
256
|
+
// `unload` on a merely `loaded` instance does not unwind, because a
|
|
257
|
+
// loaded instance is not supposed to hold anything.
|
|
258
|
+
if (!std.mem.eql(u8, e.owner.phase, "activate")) {
|
|
259
|
+
return t.fail("plugin_release_scope", "release called outside activate", null);
|
|
260
|
+
}
|
|
261
|
+
// SYMMETRIC WITH `acquire`, and it has to be: `open` counts the
|
|
262
|
+
// resources CURRENTLY HELD, so an entry that is registered and then
|
|
263
|
+
// unwound must leave the count where it found it. Incrementing on
|
|
264
|
+
// registration and never decrementing made every `release` a
|
|
265
|
+
// permanent leak in the counter.
|
|
266
|
+
_ = pushscope(e, f, ctx, true);
|
|
267
|
+
e.owner.open += 1;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
pub fn bind(
|
|
271
|
+
e: *Inst,
|
|
272
|
+
pt: []const u8,
|
|
273
|
+
hook: ?point.HookFn,
|
|
274
|
+
chain: ?point.ChainFn,
|
|
275
|
+
ctx: ?*anyopaque,
|
|
276
|
+
band: ?*v.Value,
|
|
277
|
+
) t.Err!void {
|
|
278
|
+
const h = e.owner;
|
|
279
|
+
// §12's `plugin_bind_scope`: "binding declared outside `define`".
|
|
280
|
+
// §8.1 puts binding declaration in `define` and insertion at a
|
|
281
|
+
// SUCCESSFUL activate, and the guard was the half that never got
|
|
282
|
+
// written — so a binding added from `activate` went live without
|
|
283
|
+
// being part of the loaded definition, and a deactivate/activate
|
|
284
|
+
// cycle appended it again. The code was in the table before anything
|
|
285
|
+
// raised it.
|
|
286
|
+
if (!std.mem.eql(u8, h.phase, "define")) {
|
|
287
|
+
const d = v.vmap();
|
|
288
|
+
v.set(d, "ref", v.vstr(e.ref));
|
|
289
|
+
v.set(d, "point", v.vstr(pt));
|
|
290
|
+
return t.fail("plugin_bind_scope", v.print("bind called outside define: {s}", .{pt}), d);
|
|
291
|
+
}
|
|
292
|
+
if (!v.has(h.points, pt)) {
|
|
293
|
+
return t.fail("plugin_point_unknown", v.print("no such point: {s}", .{pt}), t.details1("point", v.vstr(pt)));
|
|
294
|
+
}
|
|
295
|
+
e.bindings.append(.{
|
|
296
|
+
.ref = e.ref,
|
|
297
|
+
.point = v.dupe(pt),
|
|
298
|
+
.band = if (v.isNum(band)) v.asNum(band) else 0,
|
|
299
|
+
.hook = hook,
|
|
300
|
+
.chain = chain,
|
|
301
|
+
.ctx = ctx,
|
|
302
|
+
}) catch @panic("oom");
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
pub fn exportvalue(e: *Inst, key: []const u8, value: ?*v.Value) void {
|
|
306
|
+
v.set(e.exports, key, value);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
pub fn provides(e: *Inst, p: ?*v.Value) void {
|
|
310
|
+
v.push(e.provides, p);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// ---------------------------------------------------------------------
|
|
314
|
+
// running a callback
|
|
315
|
+
// ---------------------------------------------------------------------
|
|
316
|
+
|
|
317
|
+
fn run(h: *Host, e: *Inst, at: []const u8) t.Err!void {
|
|
318
|
+
const f = catalog.callbackFor(e.def, at);
|
|
319
|
+
|
|
320
|
+
v.push(h.log, v.vstr(v.print("{s}:{s}", .{ e.ref, at })));
|
|
321
|
+
const ev = v.vmap();
|
|
322
|
+
v.set(ev, "ref", v.vstr(e.ref));
|
|
323
|
+
v.set(ev, "event", v.vstr(at));
|
|
324
|
+
v.set(ev, "seq", v.vnum(e.seq));
|
|
325
|
+
v.set(ev, "status", v.vstr(e.status));
|
|
326
|
+
v.push(h.events, ev);
|
|
327
|
+
|
|
328
|
+
const cb = f orelse return;
|
|
329
|
+
|
|
330
|
+
h.intransition = true;
|
|
331
|
+
h.phase = at;
|
|
332
|
+
cb(e) catch {
|
|
333
|
+
h.intransition = false;
|
|
334
|
+
h.phase = "";
|
|
335
|
+
// TAKE FIRST. `pending` holds one error, and everything below
|
|
336
|
+
// this line can raise.
|
|
337
|
+
const err = t.take();
|
|
338
|
+
// §12: `plugin_define_failed` and its three siblings are "a
|
|
339
|
+
// callback raised; wraps the cause". AN ERROR THAT ALREADY
|
|
340
|
+
// CARRIES A CODE KEEPS IT — the code is the error's identity,
|
|
341
|
+
// and a plugin that raised `store_unreachable` must not have it
|
|
342
|
+
// rewritten. Only a code-less error is wrapped, which is the
|
|
343
|
+
// ordinary case for a callback that let a library error escape.
|
|
344
|
+
if (err.code.len > 0 and !std.mem.eql(u8, err.code, "plugin_bare")) {
|
|
345
|
+
return t.reraise(err);
|
|
346
|
+
}
|
|
347
|
+
const d = v.vmap();
|
|
348
|
+
v.set(d, "ref", v.vstr(e.ref));
|
|
349
|
+
v.set(d, "cause", v.vstr(err.text));
|
|
350
|
+
return t.fail(v.print("plugin_{s}_failed", .{at}), v.print("{s} raised in {s}: {s}", .{ e.ref, at, err.text }), d);
|
|
351
|
+
};
|
|
352
|
+
h.intransition = false;
|
|
353
|
+
h.phase = "";
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// ---------------------------------------------------------------------
|
|
357
|
+
// requirements and providers
|
|
358
|
+
// ---------------------------------------------------------------------
|
|
359
|
+
|
|
360
|
+
fn providersof(h: *Host, req: ?*v.Value) *v.Value {
|
|
361
|
+
const cands = v.vlist();
|
|
362
|
+
// ASK WHETHER THE NAME IS A REF, do not assume it. A requirement
|
|
363
|
+
// name is a CAPABILITY name first (§11.1) and capability names are
|
|
364
|
+
// free-form, so `2fa` and `my cap` are legal ones that no ref could
|
|
365
|
+
// be called — and `canonref` FAILS on those, which made a perfectly
|
|
366
|
+
// legal document kill the host right here.
|
|
367
|
+
const rname = v.get(req, "name");
|
|
368
|
+
const asref = if (v.isStr(rname)) ref.tryref(v.asStr(rname)) else null;
|
|
369
|
+
|
|
370
|
+
for (sortedrefs(h)) |r| {
|
|
371
|
+
const tinst = find(h, r) orelse continue;
|
|
372
|
+
if (!std.mem.eql(u8, tinst.status, "live")) continue;
|
|
373
|
+
// A ref satisfies directly.
|
|
374
|
+
if (asref != null and std.mem.eql(u8, r, asref.?)) {
|
|
375
|
+
const prov = v.vmap();
|
|
376
|
+
v.set(prov, "name", rname);
|
|
377
|
+
const c = v.vmap();
|
|
378
|
+
v.set(c, "ref", v.vstr(r));
|
|
379
|
+
v.set(c, "pos", v.vnum(tinst.pos));
|
|
380
|
+
v.set(c, "provides", prov);
|
|
381
|
+
v.push(cands, c);
|
|
382
|
+
continue;
|
|
383
|
+
}
|
|
384
|
+
for (v.items(tinst.provides)) |p| {
|
|
385
|
+
if (v.same(v.get(p, "name"), rname)) {
|
|
386
|
+
const c = v.vmap();
|
|
387
|
+
v.set(c, "ref", v.vstr(r));
|
|
388
|
+
v.set(c, "pos", v.vnum(tinst.pos));
|
|
389
|
+
v.set(c, "provides", p);
|
|
390
|
+
v.push(cands, c);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
return cap.resolvecapability(req, cands);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
fn unmetof(h: *Host, e: *Inst) *v.Value {
|
|
398
|
+
const out = v.vlist();
|
|
399
|
+
for (v.items(dep.requirements(e.options))) |r| {
|
|
400
|
+
if (!dep.gatesactivation(r)) continue;
|
|
401
|
+
if (v.len(providersof(h, r)) == 0) v.push(out, v.get(r, "name"));
|
|
402
|
+
}
|
|
403
|
+
return out;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/// §11.4's always-reluctant selection, and the ONE place a provider is
|
|
407
|
+
/// chosen for a live instance. "A satisfied requirement is not re-bound
|
|
408
|
+
/// while it stays satisfied" is a statement about a REMEMBERED choice.
|
|
409
|
+
///
|
|
410
|
+
/// `remember` is false for the questions asked ABOUT an instance rather
|
|
411
|
+
/// than BY it — introspection must not create a binding.
|
|
412
|
+
fn chosen(h: *Host, e: *Inst, req: ?*v.Value, remember: bool) ?[]const u8 {
|
|
413
|
+
const cands = providersof(h, req);
|
|
414
|
+
if (v.len(cands) == 0) return null;
|
|
415
|
+
const name = v.asStr(v.get(req, "name"));
|
|
416
|
+
const heldv = v.get(e.selected, name);
|
|
417
|
+
if (v.isStr(heldv)) {
|
|
418
|
+
for (v.items(cands)) |c| {
|
|
419
|
+
if (std.mem.eql(u8, v.asStr(v.get(c, "ref")), v.asStr(heldv))) return v.asStr(heldv);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
const first = v.asStr(v.get(v.at(cands, 0), "ref"));
|
|
423
|
+
if (remember) v.set(e.selected, name, v.vstr(first));
|
|
424
|
+
return first;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/// The instance currently SELECTED for each of this one's
|
|
428
|
+
/// restart-causing requirements. A BINDING IS TO AN INSTANCE, not to a
|
|
429
|
+
/// capability (§11.1): the selected one going away restarts a `static`
|
|
430
|
+
/// consumer even though a survivor is available.
|
|
431
|
+
fn boundproviders(h: *Host, e: *Inst) [][]const u8 {
|
|
432
|
+
var out = v.List([]const u8).init(v.arena());
|
|
433
|
+
for (v.items(dep.requirements(e.options))) |r| {
|
|
434
|
+
if (!dep.restartsonloss(r)) continue;
|
|
435
|
+
const p = chosen(h, e, r, false) orelse continue;
|
|
436
|
+
var dup = false;
|
|
437
|
+
for (out.items) |x| {
|
|
438
|
+
if (std.mem.eql(u8, x, p)) {
|
|
439
|
+
dup = true;
|
|
440
|
+
break;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
if (!dup) out.append(p) catch @panic("oom");
|
|
444
|
+
}
|
|
445
|
+
return out.items;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
fn consumersof(h: *Host, r: []const u8) [][]const u8 {
|
|
449
|
+
var out = v.List([]const u8).init(v.arena());
|
|
450
|
+
for (sortedrefs(h)) |c| {
|
|
451
|
+
if (std.mem.eql(u8, c, r)) continue;
|
|
452
|
+
const ci = find(h, c) orelse continue;
|
|
453
|
+
if (!std.mem.eql(u8, ci.status, "live")) continue;
|
|
454
|
+
for (boundproviders(h, ci)) |p| {
|
|
455
|
+
if (std.mem.eql(u8, p, r)) {
|
|
456
|
+
out.append(c) catch @panic("oom");
|
|
457
|
+
break;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
return out.items;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/// §11.3's `hold` asks a DIFFERENT question from the cascade.
|
|
465
|
+
///
|
|
466
|
+
/// The cascade wants the edges that RESTART — mandatory-static and
|
|
467
|
+
/// optional-static. `hold` says "deactivating a REQUIRED instance is
|
|
468
|
+
/// `plugin_dependency_held`", and `required` is CARDINALITY:
|
|
469
|
+
/// `gatesactivation`, not `restartsonloss`. The two sets differ in both
|
|
470
|
+
/// directions and each difference was a real bug.
|
|
471
|
+
fn holdersof(h: *Host, r: []const u8) [][]const u8 {
|
|
472
|
+
var out = v.List([]const u8).init(v.arena());
|
|
473
|
+
for (sortedrefs(h)) |c| {
|
|
474
|
+
if (std.mem.eql(u8, c, r)) continue;
|
|
475
|
+
const ci = find(h, c) orelse continue;
|
|
476
|
+
if (!std.mem.eql(u8, ci.status, "live")) continue;
|
|
477
|
+
for (v.items(dep.requirements(ci.options))) |req| {
|
|
478
|
+
if (!dep.gatesactivation(req)) continue;
|
|
479
|
+
const sel = chosen(h, ci, req, false) orelse continue;
|
|
480
|
+
if (std.mem.eql(u8, sel, r)) {
|
|
481
|
+
out.append(c) catch @panic("oom");
|
|
482
|
+
break;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
return out.items;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/// The hold check is A GUARD ON AD-HOC DEACTIVATION, NOT ON COORDINATED
|
|
490
|
+
/// TEARDOWN. In a bulk operation that is removing the holders too, it is
|
|
491
|
+
/// suspended — otherwise `close()` under `hold` would raise on the first
|
|
492
|
+
/// provider it reached whenever a document happened to list a consumer
|
|
493
|
+
/// after it, which is the policy refusing the one teardown it has no
|
|
494
|
+
/// reason to object to.
|
|
495
|
+
fn held(h: *Host, e: *Inst) t.Err!void {
|
|
496
|
+
if (!std.mem.eql(u8, h.dependency, "hold")) return;
|
|
497
|
+
if (h.coordinated) return;
|
|
498
|
+
const holders = holdersof(h, e.ref);
|
|
499
|
+
if (holders.len == 0) return;
|
|
500
|
+
const list_ = v.vlist();
|
|
501
|
+
for (holders) |x| v.push(list_, v.vstr(x));
|
|
502
|
+
const d = v.vmap();
|
|
503
|
+
v.set(d, "ref", v.vstr(e.ref));
|
|
504
|
+
v.set(d, "holders", list_);
|
|
505
|
+
return t.fail("plugin_dependency_held", v.print("instance is required by live consumers: {s}", .{e.ref}), d);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/// The requirement graph as plain data, for the pure detector.
|
|
509
|
+
fn graphnodes(h: *Host) *v.Value {
|
|
510
|
+
const out = v.vlist();
|
|
511
|
+
for (sortedrefs(h)) |r| {
|
|
512
|
+
const e = find(h, r) orelse continue;
|
|
513
|
+
const provs = v.vlist();
|
|
514
|
+
for (v.items(e.provides)) |p| v.push(provs, v.get(p, "name"));
|
|
515
|
+
const node = v.vmap();
|
|
516
|
+
v.set(node, "ref", v.vstr(r));
|
|
517
|
+
v.set(node, "provides", provs);
|
|
518
|
+
v.set(node, "requires", dep.requirements(e.options));
|
|
519
|
+
v.push(out, node);
|
|
520
|
+
}
|
|
521
|
+
return out;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
// ---------------------------------------------------------------------
|
|
525
|
+
// ordering and points
|
|
526
|
+
// ---------------------------------------------------------------------
|
|
527
|
+
|
|
528
|
+
fn lessSeq(_: void, a: *Inst, b: *Inst) bool {
|
|
529
|
+
return a.seq < b.seq;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
pub fn order(h: *Host, pt: []const u8) t.Err!*v.Value {
|
|
533
|
+
// Sorted by declaration SEQUENCE, which is what makes the §7 sort's
|
|
534
|
+
// fall-through deterministic in a language whose containers have no
|
|
535
|
+
// insertion order. §7 breaks ties by `pos`; two instances CAN share
|
|
536
|
+
// one — `declare` defaults `pos` to the registry size, so an unload
|
|
537
|
+
// followed by a fresh declare reuses a surviving instance's — and
|
|
538
|
+
// past that the canonical was falling through to map order. `seq` is
|
|
539
|
+
// that order, made explicit. Found by review of the go port.
|
|
540
|
+
var live = v.List(*Inst).init(v.arena());
|
|
541
|
+
for (h.instances.items) |e| {
|
|
542
|
+
if (std.mem.eql(u8, e.status, "live")) live.append(e) catch @panic("oom");
|
|
543
|
+
}
|
|
544
|
+
std.mem.sort(*Inst, live.items, {}, lessSeq);
|
|
545
|
+
|
|
546
|
+
const bindings = v.vlist();
|
|
547
|
+
for (live.items) |e| {
|
|
548
|
+
const b = v.vmap();
|
|
549
|
+
v.set(b, "ref", v.vstr(e.ref));
|
|
550
|
+
v.set(b, "pos", v.vnum(e.pos));
|
|
551
|
+
if (!v.isNull(e.order)) v.set(b, "order", e.order);
|
|
552
|
+
v.push(bindings, b);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
const spec = if (pt.len == 0) v.vnull() else v.get(h.points, pt);
|
|
556
|
+
return ord.resolveorder(bindings, if (v.isMap(spec)) v.get(spec, "pin") else null);
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
pub fn positionof(h: *Host, r0: []const u8, pt: []const u8) t.Err!*v.Value {
|
|
560
|
+
const ranked = try order(h, pt);
|
|
561
|
+
const r = try ref.canonrefs(r0);
|
|
562
|
+
var index: f64 = -1;
|
|
563
|
+
for (v.items(ranked), 0..) |x, i| {
|
|
564
|
+
if (std.mem.eql(u8, v.asStr(x), r)) {
|
|
565
|
+
index = @floatFromInt(i);
|
|
566
|
+
break;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
const out = v.vmap();
|
|
570
|
+
v.set(out, "index", v.vnum(index));
|
|
571
|
+
v.set(out, "count", v.vnum(@floatFromInt(v.len(ranked))));
|
|
572
|
+
// §6.2 composes b1(b2(b3(base))) with the FIRST binding OUTERMOST,
|
|
573
|
+
// so these are not index 0 and count-1 the other way round. Getting
|
|
574
|
+
// this backwards is the exact error the positional pin vocabulary
|
|
575
|
+
// exists to prevent.
|
|
576
|
+
v.set(out, "outermost", v.vbool(index == 0));
|
|
577
|
+
v.set(out, "innermost", v.vbool(index == @as(f64, @floatFromInt(v.len(ranked))) - 1));
|
|
578
|
+
return out;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
pub fn position(e: *Inst, pt: []const u8) t.Err!*v.Value {
|
|
582
|
+
return positionof(e.owner, e.ref, pt);
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/// Live bindings on a point, in resolved order. Recomputed on any change
|
|
586
|
+
/// to the live set (§7) rather than cached at startup — the bug a host
|
|
587
|
+
/// discovers only when something deactivates in production.
|
|
588
|
+
fn boundon(h: *Host, pt: []const u8) t.Err![]point.Bound {
|
|
589
|
+
const ranked = try order(h, pt);
|
|
590
|
+
var out = v.List(point.Bound).init(v.arena());
|
|
591
|
+
for (v.items(ranked)) |rv| {
|
|
592
|
+
const e = find(h, v.asStr(rv)) orelse continue;
|
|
593
|
+
// The band is the INSTANCE's ordering block (§7), stamped by the
|
|
594
|
+
// host. A plugin passing its own would be ranking itself above
|
|
595
|
+
// the order its document declared.
|
|
596
|
+
const band = v.get(e.order, "band");
|
|
597
|
+
const bandv: f64 = if (v.isNum(band)) v.asNum(band) else 0;
|
|
598
|
+
for (e.bindings.items) |b| {
|
|
599
|
+
if (!std.mem.eql(u8, b.point, pt)) continue;
|
|
600
|
+
var copy = b;
|
|
601
|
+
copy.band = bandv;
|
|
602
|
+
out.append(copy) catch @panic("oom");
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
return out.items;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
fn pointspec(h: *Host, pt: []const u8) t.Err!*v.Value {
|
|
609
|
+
if (!v.has(h.points, pt)) {
|
|
610
|
+
return t.fail("plugin_point_unknown", v.print("no such point: {s}", .{pt}), t.details1("point", v.vstr(pt)));
|
|
611
|
+
}
|
|
612
|
+
const spec = v.get(h.points, pt);
|
|
613
|
+
return if (v.isMap(spec)) spec else v.vmap();
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
fn checkkind(spec: ?*v.Value, pt: []const u8, want: []const u8) t.Err!void {
|
|
617
|
+
const kind = v.get(spec, "kind");
|
|
618
|
+
const given = v.isStr(kind);
|
|
619
|
+
const ok = if (given) std.mem.eql(u8, v.asStr(kind), want) else std.mem.eql(u8, want, "hook");
|
|
620
|
+
if (ok) return;
|
|
621
|
+
const d = v.vmap();
|
|
622
|
+
v.set(d, "point", v.vstr(pt));
|
|
623
|
+
v.set(d, "kind", if (given) kind else v.vnull());
|
|
624
|
+
return t.fail("plugin_point_kind", v.print("point is not a {s}: {s}", .{ want, pt }), d);
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
pub fn emit(h: *Host, pt: []const u8, arg: ?*v.Value) t.Err!?*v.Value {
|
|
628
|
+
const spec = try pointspec(h, pt);
|
|
629
|
+
try checkkind(spec, pt, "hook");
|
|
630
|
+
const bindings = try boundon(h, pt);
|
|
631
|
+
const mode = v.get(spec, "mode");
|
|
632
|
+
const m = if (v.isStr(mode)) v.asStr(mode) else "emit";
|
|
633
|
+
const res = try point.pointemit(bindings, m, arg);
|
|
634
|
+
if (std.mem.eql(u8, m, "emit")) return null;
|
|
635
|
+
if (std.mem.eql(u8, m, "bail")) return res.value;
|
|
636
|
+
return res.errors;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
pub fn call(h: *Host, pt: []const u8, arg: ?*v.Value) t.Err!?*v.Value {
|
|
640
|
+
const spec = try pointspec(h, pt);
|
|
641
|
+
try checkkind(spec, pt, "chain");
|
|
642
|
+
const bindings = try boundon(h, pt);
|
|
643
|
+
// The host owns the base and a plugin cannot replace it (§6.2). One
|
|
644
|
+
// that wants to SUBSTITUTE rather than wrap binds innermost and
|
|
645
|
+
// simply does not call `next`.
|
|
646
|
+
for (h.bases) |b| {
|
|
647
|
+
if (std.mem.eql(u8, b.point, pt)) return point.pointcall(bindings, b.func, null, arg);
|
|
648
|
+
}
|
|
649
|
+
return point.pointcall(bindings, null, null, arg);
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
pub fn provider(h: *Host, pt: []const u8, arg: ?*v.Value) t.Err!?*v.Value {
|
|
653
|
+
const spec = try pointspec(h, pt);
|
|
654
|
+
try checkkind(spec, pt, "provider");
|
|
655
|
+
const bindings = try boundon(h, pt);
|
|
656
|
+
const res = try point.pointprovider(bindings, v.truthy(v.get(spec, "exclusive")));
|
|
657
|
+
const w = res.winner orelse return v.get(spec, "default");
|
|
658
|
+
return w.hook.?(arg, w.ctx);
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
pub fn shadowed(h: *Host, pt: []const u8) t.Err!*v.Value {
|
|
662
|
+
if (!v.has(h.points, pt)) return v.vlist();
|
|
663
|
+
const spec = v.get(h.points, pt);
|
|
664
|
+
const bindings = try boundon(h, pt);
|
|
665
|
+
const res = try point.pointprovider(bindings, v.isMap(spec) and v.truthy(v.get(spec, "exclusive")));
|
|
666
|
+
return res.shadowed;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
pub fn exports(h: *Host, spec: []const u8) t.Err!?*v.Value {
|
|
670
|
+
const all = v.vlist();
|
|
671
|
+
for (sortedrefs(h)) |r| {
|
|
672
|
+
const e = find(h, r) orelse continue;
|
|
673
|
+
// Exports of a `loaded` (not live) instance are VISIBLE (§11).
|
|
674
|
+
if (std.mem.eql(u8, e.status, "declared") or std.mem.eql(u8, e.status, "failed")) continue;
|
|
675
|
+
for (v.keys(e.exports)) |k| {
|
|
676
|
+
const ex = v.vmap();
|
|
677
|
+
v.set(ex, "ref", v.vstr(r));
|
|
678
|
+
v.set(ex, "key", v.vstr(k));
|
|
679
|
+
v.set(ex, "value", v.get(e.exports, k));
|
|
680
|
+
v.push(all, ex);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
return exp.resolveexport(v.vstr(spec), all);
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
pub fn capability(h: *Host, name: []const u8) *v.Value {
|
|
687
|
+
const cands = v.vlist();
|
|
688
|
+
for (sortedrefs(h)) |r| {
|
|
689
|
+
const e = find(h, r) orelse continue;
|
|
690
|
+
if (!std.mem.eql(u8, e.status, "live")) continue;
|
|
691
|
+
for (v.items(e.provides)) |p| {
|
|
692
|
+
if (v.isStr(v.get(p, "name")) and std.mem.eql(u8, v.asStr(v.get(p, "name")), name)) {
|
|
693
|
+
const c = v.vmap();
|
|
694
|
+
v.set(c, "ref", v.vstr(r));
|
|
695
|
+
v.set(c, "pos", v.vnum(e.pos));
|
|
696
|
+
v.set(c, "provides", p);
|
|
697
|
+
v.push(cands, c);
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
const req = v.vmap();
|
|
702
|
+
v.set(req, "name", v.vstr(name));
|
|
703
|
+
const ranked = cap.resolvecapability(req, cands);
|
|
704
|
+
const out = v.vlist();
|
|
705
|
+
for (v.items(ranked)) |c| v.push(out, v.get(c, "ref"));
|
|
706
|
+
return out;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// ---------------------------------------------------------------------
|
|
710
|
+
// the state machine
|
|
711
|
+
// ---------------------------------------------------------------------
|
|
712
|
+
|
|
713
|
+
/// AUTO-TAGGING IS EXPLICIT (§4 rule 3): the LOWEST UNUSED POSITIVE
|
|
714
|
+
/// INTEGER tag. It needs a host because it must know what is already
|
|
715
|
+
/// declared, which is why it cannot live in the pure `ref` section.
|
|
716
|
+
pub fn autotag(h: *Host, name: []const u8) t.Err![]const u8 {
|
|
717
|
+
var n: i32 = 1;
|
|
718
|
+
while (true) : (n += 1) {
|
|
719
|
+
const cand = try ref.formatref(v.vstr(name), v.vstr(v.print("{d}", .{n})));
|
|
720
|
+
if (find(h, cand) == null) return cand;
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
pub fn declare(h: *Host, r0: []const u8, spec: DeclareSpec) t.Err!*Inst {
|
|
725
|
+
const r = if (std.mem.eql(u8, spec.tag, "?"))
|
|
726
|
+
try autotag(h, ref.refname(try ref.canonrefs(r0)))
|
|
727
|
+
else
|
|
728
|
+
try ref.canonrefs(r0);
|
|
729
|
+
|
|
730
|
+
if (!spec.hostowned) try checkreserved(h, r);
|
|
731
|
+
|
|
732
|
+
const defname = if (spec.definition.len == 0) ref.refname(r) else spec.definition;
|
|
733
|
+
const def = h.catalog.get(defname) orelse
|
|
734
|
+
return t.fail("plugin_unknown_definition", v.print("not in catalog: {s}", .{defname}), t.details1("name", v.vstr(defname)));
|
|
735
|
+
|
|
736
|
+
if (find(h, r)) |existing| {
|
|
737
|
+
// §4 rule 1: a pair addresses at most one instance. Re-declaring
|
|
738
|
+
// the SAME definition is the idempotent case; a different one is
|
|
739
|
+
// a duplicate, not a silent overwrite (seneca) and not an
|
|
740
|
+
// impossibility (sdkgen).
|
|
741
|
+
if (!std.mem.eql(u8, existing.def.name, def.name)) {
|
|
742
|
+
return t.fail("plugin_ref_duplicate", v.print("instance already declared: {s}", .{r}), t.details1("ref", v.vstr(r)));
|
|
743
|
+
}
|
|
744
|
+
return existing;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
const e = v.arena().create(Inst) catch @panic("oom");
|
|
748
|
+
e.* = .{
|
|
749
|
+
.ref = v.dupe(r),
|
|
750
|
+
.def = def,
|
|
751
|
+
.status = "declared",
|
|
752
|
+
.pos = spec.pos orelse @floatFromInt(h.instances.items.len),
|
|
753
|
+
.seq = h.seqn,
|
|
754
|
+
// NO OPTIONS ADOPTED HERE. `apply` resolves options and hands
|
|
755
|
+
// the map over; adopting the caller's map made target and source
|
|
756
|
+
// THE SAME MAP in the refill that follows, which cleared its own
|
|
757
|
+
// source and left a first-time instance with no options at all.
|
|
758
|
+
.options = if (v.isMap(spec.options)) spec.options.? else v.vmap(),
|
|
759
|
+
.state = v.vmap(),
|
|
760
|
+
.order = spec.order,
|
|
761
|
+
.selected = v.vmap(),
|
|
762
|
+
.unmet = v.vlist(),
|
|
763
|
+
.scope = v.List(*ScopeEntry).init(v.arena()),
|
|
764
|
+
.bindings = v.List(point.Bound).init(v.arena()),
|
|
765
|
+
.exports = v.vmap(),
|
|
766
|
+
.provides = v.vlist(),
|
|
767
|
+
.owner = h,
|
|
768
|
+
};
|
|
769
|
+
h.seqn += 1;
|
|
770
|
+
h.instances.append(e) catch @panic("oom");
|
|
771
|
+
return e;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
pub fn load(h: *Host, r: []const u8, spec: DeclareSpec) t.Err!*Inst {
|
|
775
|
+
try guard(h);
|
|
776
|
+
const e = try declare(h, r, spec);
|
|
777
|
+
if (!std.mem.eql(u8, e.status, "declared")) return e; // idempotent
|
|
778
|
+
// PRESENT AND NOT NULL, not merely present. Every driver builds its
|
|
779
|
+
// command spec with all four keys and a null for each absent one, so
|
|
780
|
+
// a presence test reads an omitted `options` as an authored empty
|
|
781
|
+
// and wipes the real ones.
|
|
782
|
+
if (v.isMap(spec.options)) e.options = spec.options.?;
|
|
783
|
+
|
|
784
|
+
run(h, e, "define") catch {
|
|
785
|
+
e.status = "failed";
|
|
786
|
+
return error.Plugin;
|
|
787
|
+
};
|
|
788
|
+
e.status = "loaded";
|
|
789
|
+
|
|
790
|
+
// AT LOAD, and before anything runs: a cycle through restart-causing
|
|
791
|
+
// requirements does not settle, and the only safe time to report a
|
|
792
|
+
// non-terminating reconcile is before it starts (§11.3). `provides`
|
|
793
|
+
// is populated by `define`, which has just run, so this is the first
|
|
794
|
+
// moment the graph is complete.
|
|
795
|
+
dep.checkcycle(graphnodes(h)) catch {
|
|
796
|
+
e.status = "failed";
|
|
797
|
+
return error.Plugin;
|
|
798
|
+
};
|
|
799
|
+
return e;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
/// CONSUMERS GO DOWN FIRST, NOT AFTERWARDS (§11.3).
|
|
803
|
+
///
|
|
804
|
+
/// The cascade is part of the provider's own deactivation and runs
|
|
805
|
+
/// BEFORE the provider's `deactivate` callback and scope unwind, so a
|
|
806
|
+
/// consumer's teardown can still call the thing it depends on — flushing
|
|
807
|
+
/// a buffer to the store it is about to lose is exactly what a
|
|
808
|
+
/// `deactivate` callback is for.
|
|
809
|
+
fn cascade(h: *Host, prov: *Inst, seen: *v.Value) void {
|
|
810
|
+
if (v.has(seen, prov.ref)) return;
|
|
811
|
+
v.set(seen, prov.ref, v.vbool(true));
|
|
812
|
+
|
|
813
|
+
for (consumersof(h, prov.ref)) |cref| {
|
|
814
|
+
const c = find(h, cref) orelse continue;
|
|
815
|
+
if (!std.mem.eql(u8, c.status, "live")) continue;
|
|
816
|
+
cascade(h, c, seen); // deepest-first
|
|
817
|
+
var bad = false;
|
|
818
|
+
run(h, c, "deactivate") catch {
|
|
819
|
+
_ = t.take();
|
|
820
|
+
bad = true;
|
|
821
|
+
};
|
|
822
|
+
const errors = unwind(h, c);
|
|
823
|
+
if (bad or v.len(errors) > 0) {
|
|
824
|
+
// §5.2: ANY failure during a transition lands the instance
|
|
825
|
+
// in `failed`, and a cascaded consumer is not an exception.
|
|
826
|
+
// Marking it `pending` instead handed it straight back to
|
|
827
|
+
// `reconcile`, which would activate it again the moment the
|
|
828
|
+
// provider returned — the one thing `failed` exists to stop.
|
|
829
|
+
c.status = "failed";
|
|
830
|
+
continue;
|
|
831
|
+
}
|
|
832
|
+
c.status = "pending";
|
|
833
|
+
c.unmet = unmetof(h, c);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
pub fn activate(h: *Host, r: []const u8) t.Err!*Inst {
|
|
838
|
+
try guard(h);
|
|
839
|
+
const e = try need(h, r);
|
|
840
|
+
if (std.mem.eql(u8, e.status, "live")) return e; // no-op returning success
|
|
841
|
+
if (std.mem.eql(u8, e.status, "failed")) {
|
|
842
|
+
return t.fail("plugin_bad_state", v.print("instance has failed: {s}", .{e.ref}), t.details1("ref", v.vstr(e.ref)));
|
|
843
|
+
}
|
|
844
|
+
// §9.6: `active: false` bars the instance from running, and the bar
|
|
845
|
+
// is on the INSTANCE rather than on the apply that set it. `ready`
|
|
846
|
+
// reaches this through `activate`, which is why one guard covers
|
|
847
|
+
// both verbs the design names.
|
|
848
|
+
if (e.barred) {
|
|
849
|
+
return t.fail("plugin_inactive", v.print("instance is barred by active: false: {s}", .{e.ref}), t.details1("ref", v.vstr(e.ref)));
|
|
850
|
+
}
|
|
851
|
+
if (std.mem.eql(u8, e.status, "declared")) _ = try load(h, e.ref, .{});
|
|
852
|
+
|
|
853
|
+
// A declared requirement that is not live means `pending`:
|
|
854
|
+
// activation is a STANDING REQUEST, not a one-shot event.
|
|
855
|
+
const unmet = unmetof(h, e);
|
|
856
|
+
if (v.len(unmet) > 0) {
|
|
857
|
+
e.unmet = unmet;
|
|
858
|
+
e.status = "pending";
|
|
859
|
+
return e;
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
run(h, e, "activate") catch {
|
|
863
|
+
// Unwind whatever the partial activation captured, in reverse.
|
|
864
|
+
const err = t.take();
|
|
865
|
+
_ = unwind(h, e);
|
|
866
|
+
e.status = "failed";
|
|
867
|
+
return t.reraise(err);
|
|
868
|
+
};
|
|
869
|
+
|
|
870
|
+
// §11.4: THE SELECTION IS MADE HERE, once, and remembered. Every
|
|
871
|
+
// later question — the cascade, `hold`, `unmet` — reads it back
|
|
872
|
+
// rather than re-ranking, which is what "always-reluctant" means.
|
|
873
|
+
for (v.items(dep.requirements(e.options))) |req| _ = chosen(h, e, req, true);
|
|
874
|
+
e.status = "live";
|
|
875
|
+
reconcile(h);
|
|
876
|
+
return e;
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
pub fn deactivate(h: *Host, r: []const u8) t.Err!*Inst {
|
|
880
|
+
try guard(h);
|
|
881
|
+
const e = try need(h, r);
|
|
882
|
+
if (std.mem.eql(u8, e.status, "loaded") or std.mem.eql(u8, e.status, "declared")) return e;
|
|
883
|
+
|
|
884
|
+
// §5.2: `unload` is THE ONLY TRANSITION OUT OF `failed`. Falling
|
|
885
|
+
// through here ran the definition's `deactivate` on an instance that
|
|
886
|
+
// never completed activation and, if that callback happened to
|
|
887
|
+
// succeed, returned it to `loaded` — from where it could be
|
|
888
|
+
// activated again, which is precisely what `failed` exists to
|
|
889
|
+
// prevent.
|
|
890
|
+
if (std.mem.eql(u8, e.status, "failed")) {
|
|
891
|
+
return t.fail("plugin_bad_state", v.print("instance has failed: {s}", .{e.ref}), t.details1("ref", v.vstr(e.ref)));
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
if (std.mem.eql(u8, e.status, "pending")) {
|
|
895
|
+
// DEACTIVATING A PENDING INSTANCE RUNS NO CALLBACK (§5.2). It
|
|
896
|
+
// never reached activate, so it holds no scope and no live
|
|
897
|
+
// bindings; running the definition's deactivate there would be
|
|
898
|
+
// teardown without matching setup. It cannot fail.
|
|
899
|
+
e.status = "loaded";
|
|
900
|
+
e.unmet = v.vlist();
|
|
901
|
+
return e;
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
try held(h, e);
|
|
905
|
+
cascade(h, e, v.vmap());
|
|
906
|
+
|
|
907
|
+
run(h, e, "deactivate") catch {
|
|
908
|
+
const err = t.take();
|
|
909
|
+
_ = unwind(h, e);
|
|
910
|
+
e.status = "failed";
|
|
911
|
+
return t.reraise(err);
|
|
912
|
+
};
|
|
913
|
+
try releasecheck(e, unwind(h, e));
|
|
914
|
+
e.status = "loaded";
|
|
915
|
+
reconcile(h);
|
|
916
|
+
return e;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
fn removeinst(h: *Host, e: *Inst) void {
|
|
920
|
+
for (h.instances.items, 0..) |x, i| {
|
|
921
|
+
if (x == e) {
|
|
922
|
+
_ = h.instances.orderedRemove(i);
|
|
923
|
+
return;
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
pub fn unload(h: *Host, r: []const u8) t.Err!void {
|
|
929
|
+
try guard(h);
|
|
930
|
+
const e = try need(h, r);
|
|
931
|
+
if (std.mem.eql(u8, e.status, "live") or std.mem.eql(u8, e.status, "pending")) {
|
|
932
|
+
if (std.mem.eql(u8, e.status, "live")) {
|
|
933
|
+
try held(h, e);
|
|
934
|
+
cascade(h, e, v.vmap());
|
|
935
|
+
run(h, e, "deactivate") catch {
|
|
936
|
+
// §5.2: ANY failure during a transition lands the
|
|
937
|
+
// instance in `failed`, with the scope STILL FULLY
|
|
938
|
+
// UNWOUND. An earlier draft let the raise propagate
|
|
939
|
+
// straight out of `unload`, which left the instance
|
|
940
|
+
// `live` and its scope untouched — reporting a failure
|
|
941
|
+
// while leaking exactly the resources the failure was
|
|
942
|
+
// about.
|
|
943
|
+
const err = t.take();
|
|
944
|
+
_ = unwind(h, e);
|
|
945
|
+
e.status = "failed";
|
|
946
|
+
return t.reraise(err);
|
|
947
|
+
};
|
|
948
|
+
try releasecheck(e, unwind(h, e));
|
|
949
|
+
}
|
|
950
|
+
e.status = "loaded";
|
|
951
|
+
}
|
|
952
|
+
if (std.mem.eql(u8, e.status, "loaded") or std.mem.eql(u8, e.status, "failed")) {
|
|
953
|
+
run(h, e, "close") catch {
|
|
954
|
+
const err = t.take();
|
|
955
|
+
removeinst(h, e);
|
|
956
|
+
return t.reraise(err);
|
|
957
|
+
};
|
|
958
|
+
}
|
|
959
|
+
removeinst(h, e);
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
pub fn ready(h: *Host, r0: []const u8) t.Err!*Inst {
|
|
963
|
+
// Runs the whole forward path in one call (§5.1). §15.2's verb list
|
|
964
|
+
// omits this; §5.1 defines it and §15.3's `declare` row requires the
|
|
965
|
+
// corpus to pin it, so the list was incomplete rather than excluding
|
|
966
|
+
// it (DOCS.md §4.2).
|
|
967
|
+
try guard(h);
|
|
968
|
+
const r = try ref.canonrefs(r0);
|
|
969
|
+
if (find(h, r) == null) _ = try declare(h, r, .{});
|
|
970
|
+
if (find(h, r)) |e| {
|
|
971
|
+
if (std.mem.eql(u8, e.status, "declared")) _ = try load(h, r, .{});
|
|
972
|
+
}
|
|
973
|
+
return activate(h, r);
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
/// EAGER reconciliation: run to a fixed point rather than scheduling.
|
|
977
|
+
///
|
|
978
|
+
/// Two directions, and both are the reason `pending` exists. Activation
|
|
979
|
+
/// is a STANDING REQUEST, not a one-shot event: a pending instance whose
|
|
980
|
+
/// requirement arrives activates without being asked again, and a LIVE
|
|
981
|
+
/// instance whose requirement is lost goes back to pending —
|
|
982
|
+
/// recursively, through its own consumers.
|
|
983
|
+
fn reconcile(h: *Host) void {
|
|
984
|
+
var moved = true;
|
|
985
|
+
var rounds: i32 = 0;
|
|
986
|
+
while (moved) {
|
|
987
|
+
moved = false;
|
|
988
|
+
rounds += 1;
|
|
989
|
+
if (rounds > 1000) break;
|
|
990
|
+
|
|
991
|
+
// Losses first, so a cascade settles in one pass rather than
|
|
992
|
+
// alternating with re-activations.
|
|
993
|
+
for (sortedrefs(h)) |r| {
|
|
994
|
+
const e = find(h, r) orelse continue;
|
|
995
|
+
if (!std.mem.eql(u8, e.status, "live")) continue;
|
|
996
|
+
const lost = v.vlist();
|
|
997
|
+
for (v.items(dep.requirements(e.options))) |q| {
|
|
998
|
+
if (!dep.gatesactivation(q)) continue;
|
|
999
|
+
if (v.len(providersof(h, q)) == 0) v.push(lost, q);
|
|
1000
|
+
}
|
|
1001
|
+
if (v.len(lost) == 0) continue;
|
|
1002
|
+
// POLICY IS PER REQUIREMENT, not per instance (§11.3): only
|
|
1003
|
+
// the definition that has the requirement knows what it can
|
|
1004
|
+
// cope with, and one instance may hold both a `static` and a
|
|
1005
|
+
// `dynamic` one. A `dynamic` requirement whose provider is
|
|
1006
|
+
// gone leaves the consumer LIVE and notified.
|
|
1007
|
+
var anyrestart = false;
|
|
1008
|
+
for (v.items(lost)) |q| {
|
|
1009
|
+
if (dep.restartsonloss(q)) {
|
|
1010
|
+
anyrestart = true;
|
|
1011
|
+
break;
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
if (!anyrestart) continue;
|
|
1015
|
+
|
|
1016
|
+
var bad = false;
|
|
1017
|
+
run(h, e, "deactivate") catch {
|
|
1018
|
+
_ = t.take();
|
|
1019
|
+
bad = true;
|
|
1020
|
+
};
|
|
1021
|
+
const errors = unwind(h, e);
|
|
1022
|
+
if (bad or v.len(errors) > 0) {
|
|
1023
|
+
e.status = "failed";
|
|
1024
|
+
} else {
|
|
1025
|
+
e.status = "pending";
|
|
1026
|
+
e.unmet = unmetof(h, e);
|
|
1027
|
+
}
|
|
1028
|
+
moved = true;
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
for (sortedrefs(h)) |r| {
|
|
1032
|
+
const e = find(h, r) orelse continue;
|
|
1033
|
+
if (!std.mem.eql(u8, e.status, "pending")) continue;
|
|
1034
|
+
if (v.len(unmetof(h, e)) > 0) continue;
|
|
1035
|
+
run(h, e, "activate") catch {
|
|
1036
|
+
_ = t.take();
|
|
1037
|
+
_ = unwind(h, e);
|
|
1038
|
+
e.status = "failed";
|
|
1039
|
+
moved = true;
|
|
1040
|
+
continue;
|
|
1041
|
+
};
|
|
1042
|
+
for (v.items(dep.requirements(e.options))) |req| _ = chosen(h, e, req, true);
|
|
1043
|
+
e.status = "live";
|
|
1044
|
+
e.unmet = v.vlist();
|
|
1045
|
+
moved = true;
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
fn lessDropOrder(h: *Host, a: []const u8, b: []const u8) bool {
|
|
1051
|
+
const x = find(h, a) orelse return false;
|
|
1052
|
+
const y = find(h, b) orelse return false;
|
|
1053
|
+
// Reverse load order: highest `pos` first, ref-descending for a tie,
|
|
1054
|
+
// so a consumer declared after its provider goes down first.
|
|
1055
|
+
if (x.pos != y.pos) return x.pos > y.pos;
|
|
1056
|
+
return std.mem.order(u8, a, b) == .gt;
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
const DropCtx = struct { h: *Host };
|
|
1060
|
+
|
|
1061
|
+
fn lessDrop(ctx: DropCtx, a: []const u8, b: []const u8) bool {
|
|
1062
|
+
return lessDropOrder(ctx.h, a, b);
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
pub fn close(h: *Host) t.Err!void {
|
|
1066
|
+
// A bulk teardown removing the holders too, so `hold` is suspended
|
|
1067
|
+
// for exactly those holders (§11.3) — while the consumers-first
|
|
1068
|
+
// cascade still runs, which is the half that matters.
|
|
1069
|
+
// A COORDINATED FLAG THAT SURVIVES A RAISE IS A DISABLED GUARD. The
|
|
1070
|
+
// canonical wraps the teardown in try/finally; an unload that raises
|
|
1071
|
+
// would skip the reset and leave the host permanently `coordinated`,
|
|
1072
|
+
// so a caller that catches the error and carries on under
|
|
1073
|
+
// `dependency: "hold"` gets ad-hoc deactivation with the holder
|
|
1074
|
+
// check silently off.
|
|
1075
|
+
//
|
|
1076
|
+
// `defer` rather than a catch: the flag is cleared on every exit
|
|
1077
|
+
// from this function, so the raising path is not written twice.
|
|
1078
|
+
h.coordinated = true;
|
|
1079
|
+
defer h.coordinated = false;
|
|
1080
|
+
const refs = v.arena().alloc([]const u8, h.instances.items.len) catch @panic("oom");
|
|
1081
|
+
for (h.instances.items, 0..) |e, i| refs[i] = e.ref;
|
|
1082
|
+
std.mem.sort([]const u8, refs, DropCtx{ .h = h }, lessDrop);
|
|
1083
|
+
for (refs) |r| {
|
|
1084
|
+
if (find(h, r) != null) try unload(h, r);
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
/// The scope entry carries the inner host as its context — zig's
|
|
1089
|
+
/// stand-in for the closure every other port with closures writes here.
|
|
1090
|
+
fn closeinner(ctx: ?*anyopaque) void {
|
|
1091
|
+
const inner: *Host = @ptrCast(@alignCast(ctx.?));
|
|
1092
|
+
close(inner) catch {
|
|
1093
|
+
release_error = t.take().message;
|
|
1094
|
+
};
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
/// AN INSTANCE MAY ITSELF BE A HOST (§6.5), and THE OUTER ONE OWNS THE
|
|
1098
|
+
/// INNER ONE'S LIFETIME. Registering the teardown in the instance scope
|
|
1099
|
+
/// is what makes that true rather than aspirational: the inner host
|
|
1100
|
+
/// closes when the outer instance deactivates, in the same reverse
|
|
1101
|
+
/// unwind as every other resource.
|
|
1102
|
+
///
|
|
1103
|
+
/// It does NOT count toward `open` — a teardown is not an acquisition
|
|
1104
|
+
/// (`nest/open`).
|
|
1105
|
+
pub fn nest(e: *Inst, o: HostOptions) t.Err!*Host {
|
|
1106
|
+
if (!e.owner.intransition) {
|
|
1107
|
+
return t.fail("plugin_release_scope", "nest called outside a lifecycle callback", null);
|
|
1108
|
+
}
|
|
1109
|
+
const inner = makehost(o);
|
|
1110
|
+
_ = pushscope(e, closeinner, inner, false);
|
|
1111
|
+
e.inner = inner;
|
|
1112
|
+
return inner;
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
// ---------------------------------------------------------------------
|
|
1116
|
+
// documents
|
|
1117
|
+
// ---------------------------------------------------------------------
|
|
1118
|
+
|
|
1119
|
+
/// Empty the target and refill it, so callers holding the reference see
|
|
1120
|
+
/// the new values. A definition's callbacks close over the options map
|
|
1121
|
+
/// they were handed at `define`; replacing the reference would leave
|
|
1122
|
+
/// every binding reading the values the first apply gave it.
|
|
1123
|
+
fn refill(target: *v.Value, source: ?*v.Value) void {
|
|
1124
|
+
for (v.keys(target)) |k| v.del(target, k);
|
|
1125
|
+
for (v.keys(source)) |k| v.set(target, k, v.get(source, k));
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
fn shapeof(h: *Host, r: []const u8) ?*v.Value {
|
|
1129
|
+
const d = h.catalog.get(ref.refname(r)) orelse return null;
|
|
1130
|
+
return d.shape;
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
fn wantlive(ent: ?*v.Value) bool {
|
|
1134
|
+
return v.isMap(ent) and v.truthy(v.get(ent, "active")) and
|
|
1135
|
+
std.mem.eql(u8, v.asStr(v.get(ent, "start")), "eager");
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
pub fn apply(h: *Host, doc: ?*v.Value, profile: ?*v.Value) t.Err!void {
|
|
1139
|
+
try guard(h);
|
|
1140
|
+
const in = v.vmap();
|
|
1141
|
+
v.set(in, "doc", doc);
|
|
1142
|
+
v.set(in, "profile", if (v.isNull(profile)) h.profile else profile);
|
|
1143
|
+
v.set(in, "keys", h.keys);
|
|
1144
|
+
v.set(in, "reserved", h.reserved);
|
|
1145
|
+
const norm = try cfg.normalizeconfig(in);
|
|
1146
|
+
|
|
1147
|
+
const want = v.get(norm, "order");
|
|
1148
|
+
const optionsof = v.vmap();
|
|
1149
|
+
for (v.items(want)) |rv| {
|
|
1150
|
+
const r = v.asStr(rv);
|
|
1151
|
+
const oin = v.vmap();
|
|
1152
|
+
v.set(oin, "ref", v.vstr(r));
|
|
1153
|
+
v.set(oin, "doc", doc);
|
|
1154
|
+
v.set(oin, "profile", if (v.isNull(profile)) h.profile else profile);
|
|
1155
|
+
v.set(oin, "shape", shapeof(h, r));
|
|
1156
|
+
if (v.isMap(h.defaults)) v.set(oin, "hostdefaults", v.get(h.defaults, ref.refname(r)));
|
|
1157
|
+
v.set(optionsof, r, try cfg.resolveoptions(oin));
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1160
|
+
// --- phase 1: deactivations and unloads, in REVERSE load order ---
|
|
1161
|
+
const instancespec = v.get(norm, "instance");
|
|
1162
|
+
var drop = v.List([]const u8).init(v.arena());
|
|
1163
|
+
for (h.instances.items) |e| {
|
|
1164
|
+
if (std.mem.eql(u8, e.status, "declared")) continue;
|
|
1165
|
+
if (!wantlive(v.get(instancespec, e.ref))) drop.append(e.ref) catch @panic("oom");
|
|
1166
|
+
}
|
|
1167
|
+
std.mem.sort([]const u8, drop.items, DropCtx{ .h = h }, lessDrop);
|
|
1168
|
+
for (drop.items) |r| try unload(h, r);
|
|
1169
|
+
|
|
1170
|
+
// --- phase 2: declare and patch EVERYTHING, in load order --------
|
|
1171
|
+
for (v.items(want)) |rv| {
|
|
1172
|
+
const r = v.asStr(rv);
|
|
1173
|
+
const ent = v.get(instancespec, r);
|
|
1174
|
+
const e = try declare(h, r, .{
|
|
1175
|
+
.order = v.get(ent, "order"),
|
|
1176
|
+
.pos = v.asNum(v.get(ent, "pos")),
|
|
1177
|
+
});
|
|
1178
|
+
// The bar is REASSERTED ON EVERY APPLY, in both directions — a
|
|
1179
|
+
// document that turns the instance back on clears it, which is
|
|
1180
|
+
// the whole point of a config switch.
|
|
1181
|
+
e.barred = !v.truthy(v.get(ent, "active"));
|
|
1182
|
+
refill(e.options, v.get(optionsof, r));
|
|
1183
|
+
e.order = v.get(ent, "order");
|
|
1184
|
+
e.pos = v.asNum(v.get(ent, "pos"));
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
// --- phase 3: loads, then phase 4: activations, in load order ----
|
|
1188
|
+
for (v.items(want)) |rv| {
|
|
1189
|
+
if (wantlive(v.get(instancespec, v.asStr(rv)))) _ = try load(h, v.asStr(rv), .{});
|
|
1190
|
+
}
|
|
1191
|
+
for (v.items(want)) |rv| {
|
|
1192
|
+
if (wantlive(v.get(instancespec, v.asStr(rv)))) _ = try activate(h, v.asStr(rv));
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
pub fn setoptions(h: *Host, r: []const u8, patch: ?*v.Value) t.Err!void {
|
|
1197
|
+
try guard(h);
|
|
1198
|
+
const e = try need(h, r);
|
|
1199
|
+
const previous = v.clone(e.options);
|
|
1200
|
+
const in = v.vmap();
|
|
1201
|
+
v.set(in, "ref", v.vstr(e.ref));
|
|
1202
|
+
v.set(in, "shape", shapeof(h, e.ref));
|
|
1203
|
+
v.set(in, "doc", v.vmap());
|
|
1204
|
+
v.set(in, "patch", t.mergeValue(previous, patch));
|
|
1205
|
+
refill(e.options, try cfg.resolveoptions(in));
|
|
1206
|
+
|
|
1207
|
+
if (!std.mem.eql(u8, e.status, "live")) return;
|
|
1208
|
+
if (e.def.reconfigure) |f| {
|
|
1209
|
+
h.intransition = true;
|
|
1210
|
+
h.phase = "reconfigure";
|
|
1211
|
+
f(e, e.options, previous) catch {
|
|
1212
|
+
h.intransition = false;
|
|
1213
|
+
h.phase = "";
|
|
1214
|
+
return error.Plugin;
|
|
1215
|
+
};
|
|
1216
|
+
h.intransition = false;
|
|
1217
|
+
h.phase = "";
|
|
1218
|
+
return;
|
|
1219
|
+
}
|
|
1220
|
+
// Always correct and sometimes expensive; `reconfigure` exists to
|
|
1221
|
+
// make the common case cheap (§9.4).
|
|
1222
|
+
_ = try deactivate(h, e.ref);
|
|
1223
|
+
_ = try activate(h, e.ref);
|
|
1224
|
+
}
|