From 0eaf4d8bd190896970501673b8969a2af03f0919 Mon Sep 17 00:00:00 2001 From: Yohe-Am <56622350+Yohe-Am@users.noreply.github.com> Date: Fri, 3 Jan 2025 12:55:34 +0300 Subject: [PATCH] docs!: user manual + 0.3.0-rc.1 (#106) --- .cargo/config.toml | 10 + .ghjk/deno.lock | 357 +- .ghjk/lock.json | 737 ++- .github/workflows/nightly.yml | 75 +- .github/workflows/release.yml | 90 + .github/workflows/tests.yml | 67 +- .gitignore | 6 + .pre-commit-config.yaml | 30 +- .vscode/settings.json | 14 +- Cargo.lock | 9366 ++++++++++++++++++++++++++++ Cargo.toml | 38 + README.md | 176 +- deno.jsonc | 14 +- deno.lock | 458 +- deps/common.ts | 2 +- deps/install.ts | 1 + docs/available-commands.md | 15 - docs/installation-vars.md | 15 + docs/known-issues.md | 28 + docs/manual.md | 483 ++ examples/env_vars/ghjk.ts | 2 +- examples/kitchen/ghjk.ts | 3 +- files/deno/bindings.ts | 35 + files/deno/mod.ts | 1 + files/deno/worker.ts | 2 +- files/mod.ts | 8 +- ghjk.ts | 162 +- hack.ts | 1 + host/init/mod.ts | 185 + host/init/template.ts | 22 + host/mod.ts | 597 -- install.sh | 180 +- install.ts | 22 +- install/bash-preexec.sh | 353 ++ install/ghjk.sh | 55 - install/hook.fish | 31 +- install/hook.sh | 31 +- install/mod.ts | 130 +- install/utils.ts | 21 +- main.ts | 43 - mod.ts | 75 +- modules/envs/mod.ts | 245 +- modules/envs/posix.ts | 62 +- modules/mod.ts | 21 +- modules/ports/ambient.ts | 6 +- modules/ports/ghrel.ts | 4 +- modules/ports/mod.ts | 350 +- modules/ports/std.ts | 16 +- modules/ports/std_runtime.ts | 17 + modules/ports/sync.ts | 13 +- modules/ports/worker.ts | 17 +- modules/tasks/mod.ts | 117 +- modules/types.ts | 2 +- ports/act.ts | 4 +- ports/asdf.ts | 10 +- ports/asdf_plugin_git.ts | 24 +- ports/cargo-binstall.ts | 4 +- ports/cargobi.ts | 6 +- ports/cmake.ts | 49 - ports/cpy_bs.ts | 8 +- ports/deno_ghrel.ts | 4 +- ports/dummy.ts | 6 +- ports/earthly.ts | 4 +- ports/fx_ghrel.ts | 72 + ports/infisical.ts | 8 +- ports/jq_ghrel.ts | 4 +- ports/livekit_cli_ghrel.ts | 90 + ports/meta_cli_ghrel.ts | 4 +- ports/mod.ts | 4 +- ports/mold.ts | 4 +- ports/node.ts | 10 +- ports/npmi.ts | 6 +- ports/opentofu_ghrel.ts | 4 +- ports/pipi.ts | 8 +- ports/pnpm.ts | 4 +- ports/poetry.ts | 8 +- ports/protoc.ts | 4 +- ports/ruff.ts | 4 +- ports/rust.ts | 6 +- ports/rustup.ts | 6 +- ports/temporal_cli.ts | 4 +- ports/terraform.ts | 6 +- ports/wasmedge.ts | 8 +- ports/zstd.ts | 2 +- rust-toolchain.toml | 6 + scripts/check.ts | 20 - scripts/dev.ts | 67 - src/deno_systems/bindings.ts | 176 + src/deno_systems/mod.ts | 10 + src/deno_systems/types.ts | 145 + src/denort/Cargo.toml | 22 + src/denort/lib.rs | 327 + src/denort/macros.rs | 16 + src/denort/promises.rs | 71 + src/denort/unsync.rs | 280 + src/denort/worker.rs | 566 ++ src/ghjk/Cargo.toml | 80 + src/ghjk/build.rs | 3 + src/ghjk/cli.rs | 442 ++ src/ghjk/config.rs | 286 + src/ghjk/ext.rs | 226 + src/ghjk/ext/callbacks.rs | 317 + src/ghjk/host.rs | 378 ++ src/ghjk/host/deno.rs | 92 + src/ghjk/host/hashfile.rs | 271 + src/ghjk/js/00_runtime.js | 44 + src/ghjk/js/mock.sfx.ts | 20 + src/ghjk/js/runtime.d.ts | 17 + src/ghjk/js/runtime.js | 10 + src/ghjk/log.rs | 100 + src/ghjk/main.rs | 72 + src/ghjk/systems.rs | 149 + src/ghjk/systems/deno.rs | 321 + src/ghjk/systems/deno/cli.rs | 400 ++ src/ghjk/utils.rs | 261 + src/play/Cargo.toml | 22 + src/play/main.rs | 20 + src/xtask/Cargo.toml | 19 + src/xtask/main.rs | 99 + src/xtask/utils.rs | 29 + std/sedLock.ts | 21 +- tests/envHooks.ts | 10 +- tests/envs.ts | 35 +- tests/hashfile.ts | 75 + tests/ports.ts | 73 +- tests/portsOutdated.ts | 24 +- tests/reloadHooks.ts | 222 +- tests/tasks.ts | 22 +- tests/test-alpine.Dockerfile | 80 - tests/test.Dockerfile | 71 - tests/test.Dockerfile.dockerignore | 4 - tests/todo.ts | 1 + tests/utils.ts | 180 +- tools/check.ts | 24 + tools/dev.ts | 78 + utils/logger.ts | 5 +- utils/mod.ts | 81 +- utils/unarchive.ts | 7 +- 138 files changed, 18697 insertions(+), 2896 deletions(-) create mode 100644 .cargo/config.toml create mode 100644 .github/workflows/release.yml create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 deps/install.ts delete mode 100644 docs/available-commands.md create mode 100644 docs/installation-vars.md create mode 100644 docs/known-issues.md create mode 100644 docs/manual.md create mode 100644 files/deno/bindings.ts create mode 100644 host/init/mod.ts create mode 100644 host/init/template.ts delete mode 100644 host/mod.ts create mode 100644 install/bash-preexec.sh delete mode 100644 install/ghjk.sh delete mode 100755 main.ts create mode 100644 modules/ports/std_runtime.ts delete mode 100644 ports/cmake.ts create mode 100644 ports/fx_ghrel.ts create mode 100644 ports/livekit_cli_ghrel.ts create mode 100644 rust-toolchain.toml delete mode 100755 scripts/check.ts delete mode 100755 scripts/dev.ts create mode 100644 src/deno_systems/bindings.ts create mode 100644 src/deno_systems/mod.ts create mode 100644 src/deno_systems/types.ts create mode 100644 src/denort/Cargo.toml create mode 100644 src/denort/lib.rs create mode 100644 src/denort/macros.rs create mode 100644 src/denort/promises.rs create mode 100644 src/denort/unsync.rs create mode 100644 src/denort/worker.rs create mode 100644 src/ghjk/Cargo.toml create mode 100644 src/ghjk/build.rs create mode 100644 src/ghjk/cli.rs create mode 100644 src/ghjk/config.rs create mode 100644 src/ghjk/ext.rs create mode 100644 src/ghjk/ext/callbacks.rs create mode 100644 src/ghjk/host.rs create mode 100644 src/ghjk/host/deno.rs create mode 100644 src/ghjk/host/hashfile.rs create mode 100644 src/ghjk/js/00_runtime.js create mode 100644 src/ghjk/js/mock.sfx.ts create mode 100644 src/ghjk/js/runtime.d.ts create mode 100644 src/ghjk/js/runtime.js create mode 100644 src/ghjk/log.rs create mode 100644 src/ghjk/main.rs create mode 100644 src/ghjk/systems.rs create mode 100644 src/ghjk/systems/deno.rs create mode 100644 src/ghjk/systems/deno/cli.rs create mode 100644 src/ghjk/utils.rs create mode 100644 src/play/Cargo.toml create mode 100644 src/play/main.rs create mode 100644 src/xtask/Cargo.toml create mode 100644 src/xtask/main.rs create mode 100644 src/xtask/utils.rs create mode 100644 tests/hashfile.ts delete mode 100644 tests/test-alpine.Dockerfile delete mode 100644 tests/test.Dockerfile delete mode 100644 tests/test.Dockerfile.dockerignore create mode 100644 tests/todo.ts create mode 100755 tools/check.ts create mode 100755 tools/dev.ts diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 00000000..53a1c12c --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,10 @@ +[alias] +xtask = "run --package xtask --" +x = "run --package xtask --" + +[build] +rustflags = [ + # for use with tokio-rs/console + "--cfg", + "tokio_unstable" +] diff --git a/.ghjk/deno.lock b/.ghjk/deno.lock index 74ec5489..8ec1e4b0 100644 --- a/.ghjk/deno.lock +++ b/.ghjk/deno.lock @@ -1,93 +1,95 @@ { - "version": "3", - "packages": { - "specifiers": { - "jsr:@david/dax@0.41.0": "jsr:@david/dax@0.41.0", - "jsr:@david/which@^0.4.1": "jsr:@david/which@0.4.1", - "jsr:@std/assert@^0.221.0": "jsr:@std/assert@0.221.0", - "jsr:@std/bytes@^0.221.0": "jsr:@std/bytes@0.221.0", - "jsr:@std/fmt@^0.221.0": "jsr:@std/fmt@0.221.0", - "jsr:@std/fs@0.221.0": "jsr:@std/fs@0.221.0", - "jsr:@std/io@0.221.0": "jsr:@std/io@0.221.0", - "jsr:@std/io@^0.221.0": "jsr:@std/io@0.221.0", - "jsr:@std/path@0.221.0": "jsr:@std/path@0.221.0", - "jsr:@std/path@^0.221.0": "jsr:@std/path@0.221.0", - "jsr:@std/streams@0.221.0": "jsr:@std/streams@0.221.0", - "npm:@noble/hashes@1.4.0": "npm:@noble/hashes@1.4.0", - "npm:multiformats@13.1.0": "npm:multiformats@13.1.0", - "npm:zod-validation-error@3.3.0": "npm:zod-validation-error@3.3.0_zod@3.23.8", - "npm:zod@3.23.8": "npm:zod@3.23.8" + "version": "4", + "specifiers": { + "jsr:@david/dax@0.41.0": "0.41.0", + "jsr:@david/which@~0.4.1": "0.4.1", + "jsr:@std/assert@0.221": "0.221.0", + "jsr:@std/bytes@0.221": "0.221.0", + "jsr:@std/fmt@0.221": "0.221.0", + "jsr:@std/fs@0.221.0": "0.221.0", + "jsr:@std/io@0.221": "0.221.0", + "jsr:@std/io@0.221.0": "0.221.0", + "jsr:@std/path@0.221": "0.221.0", + "jsr:@std/path@0.221.0": "0.221.0", + "jsr:@std/streams@0.221.0": "0.221.0", + "npm:@noble/hashes@1.4.0": "1.4.0", + "npm:multiformats@13.1.0": "13.1.0", + "npm:zod-validation-error@3.3.0": "3.3.0_zod@3.23.8", + "npm:zod-validation-error@3.4.0": "3.4.0_zod@3.23.8", + "npm:zod@3.23.8": "3.23.8" + }, + "jsr": { + "@david/dax@0.41.0": { + "integrity": "9e1ecf66a0415962cc8ad3ba4e3fa93ce0f1a1cc797dd95c36fdfb6977dc7fc8", + "dependencies": [ + "jsr:@david/which", + "jsr:@std/fmt", + "jsr:@std/fs", + "jsr:@std/io@0.221.0", + "jsr:@std/path@0.221.0", + "jsr:@std/streams" + ] + }, + "@david/which@0.4.1": { + "integrity": "896a682b111f92ab866cc70c5b4afab2f5899d2f9bde31ed00203b9c250f225e" + }, + "@std/assert@0.221.0": { + "integrity": "a5f1aa6e7909dbea271754fd4ab3f4e687aeff4873b4cef9a320af813adb489a" + }, + "@std/bytes@0.221.0": { + "integrity": "64a047011cf833890a4a2ab7293ac55a1b4f5a050624ebc6a0159c357de91966" + }, + "@std/fmt@0.221.0": { + "integrity": "379fed69bdd9731110f26b9085aeb740606b20428ce6af31ef6bd45ef8efa62a" + }, + "@std/fs@0.221.0": { + "integrity": "028044450299de8ed5a716ade4e6d524399f035513b85913794f4e81f07da286", + "dependencies": [ + "jsr:@std/assert", + "jsr:@std/path@0.221" + ] + }, + "@std/io@0.221.0": { + "integrity": "faf7f8700d46ab527fa05cc6167f4b97701a06c413024431c6b4d207caa010da", + "dependencies": [ + "jsr:@std/assert", + "jsr:@std/bytes" + ] + }, + "@std/path@0.221.0": { + "integrity": "0a36f6b17314ef653a3a1649740cc8db51b25a133ecfe838f20b79a56ebe0095", + "dependencies": [ + "jsr:@std/assert" + ] + }, + "@std/streams@0.221.0": { + "integrity": "47f2f74634b47449277c0ee79fe878da4424b66bd8975c032e3afdca88986e61", + "dependencies": [ + "jsr:@std/io@0.221" + ] + } + }, + "npm": { + "@noble/hashes@1.4.0": { + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==" + }, + "multiformats@13.1.0": { + "integrity": "sha512-HzdtdBwxsIkzpeXzhQ5mAhhuxcHbjEHH+JQoxt7hG/2HGFjjwyolLo7hbaexcnhoEuV4e0TNJ8kkpMjiEYY4VQ==" + }, + "zod-validation-error@3.3.0_zod@3.23.8": { + "integrity": "sha512-Syib9oumw1NTqEv4LT0e6U83Td9aVRk9iTXPUQr1otyV1PuXQKOvOwhMNqZIq5hluzHP2pMgnOmHEo7kPdI2mw==", + "dependencies": [ + "zod" + ] }, - "jsr": { - "@david/dax@0.41.0": { - "integrity": "9e1ecf66a0415962cc8ad3ba4e3fa93ce0f1a1cc797dd95c36fdfb6977dc7fc8", - "dependencies": [ - "jsr:@david/which@^0.4.1", - "jsr:@std/fmt@^0.221.0", - "jsr:@std/fs@0.221.0", - "jsr:@std/io@0.221.0", - "jsr:@std/path@0.221.0", - "jsr:@std/streams@0.221.0" - ] - }, - "@david/which@0.4.1": { - "integrity": "896a682b111f92ab866cc70c5b4afab2f5899d2f9bde31ed00203b9c250f225e" - }, - "@std/assert@0.221.0": { - "integrity": "a5f1aa6e7909dbea271754fd4ab3f4e687aeff4873b4cef9a320af813adb489a" - }, - "@std/bytes@0.221.0": { - "integrity": "64a047011cf833890a4a2ab7293ac55a1b4f5a050624ebc6a0159c357de91966" - }, - "@std/fmt@0.221.0": { - "integrity": "379fed69bdd9731110f26b9085aeb740606b20428ce6af31ef6bd45ef8efa62a" - }, - "@std/fs@0.221.0": { - "integrity": "028044450299de8ed5a716ade4e6d524399f035513b85913794f4e81f07da286", - "dependencies": [ - "jsr:@std/assert@^0.221.0", - "jsr:@std/path@^0.221.0" - ] - }, - "@std/io@0.221.0": { - "integrity": "faf7f8700d46ab527fa05cc6167f4b97701a06c413024431c6b4d207caa010da", - "dependencies": [ - "jsr:@std/assert@^0.221.0", - "jsr:@std/bytes@^0.221.0" - ] - }, - "@std/path@0.221.0": { - "integrity": "0a36f6b17314ef653a3a1649740cc8db51b25a133ecfe838f20b79a56ebe0095", - "dependencies": [ - "jsr:@std/assert@^0.221.0" - ] - }, - "@std/streams@0.221.0": { - "integrity": "47f2f74634b47449277c0ee79fe878da4424b66bd8975c032e3afdca88986e61", - "dependencies": [ - "jsr:@std/io@^0.221.0" - ] - } + "zod-validation-error@3.4.0_zod@3.23.8": { + "integrity": "sha512-ZOPR9SVY6Pb2qqO5XHt+MkkTRxGXb4EVtnjc9JpXUOtUB1T9Ru7mZOT361AN3MsetVe7R0a1KZshJDZdgp9miQ==", + "dependencies": [ + "zod" + ] }, - "npm": { - "@noble/hashes@1.4.0": { - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "dependencies": {} - }, - "multiformats@13.1.0": { - "integrity": "sha512-HzdtdBwxsIkzpeXzhQ5mAhhuxcHbjEHH+JQoxt7hG/2HGFjjwyolLo7hbaexcnhoEuV4e0TNJ8kkpMjiEYY4VQ==", - "dependencies": {} - }, - "zod-validation-error@3.3.0_zod@3.23.8": { - "integrity": "sha512-Syib9oumw1NTqEv4LT0e6U83Td9aVRk9iTXPUQr1otyV1PuXQKOvOwhMNqZIq5hluzHP2pMgnOmHEo7kPdI2mw==", - "dependencies": { - "zod": "zod@3.23.8" - } - }, - "zod@3.23.8": { - "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", - "dependencies": {} - } + "zod@3.23.8": { + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==" } }, "remote": { @@ -394,144 +396,51 @@ "https://deno.land/x/foras@v2.1.4/wasm/pkg/foras.wasm.js": "2df8522df7243b0f05b1d188e220629cd5d2c92080a5f1407e15396fc35bebb3", "https://deno.land/x/json_hash@0.2.0/canon.ts": "ce7c07abd871cd7f0eb1280ad9f58f6382f02f84a217898ce977cf35ad315877", "https://deno.land/x/jszip@0.11.0/mod.ts": "5661ddc18e9ac9c07e3c5d2483bc912a7022b6af0d784bb7b05035973e640ba1", - "https://deno.land/x/zod@v3.23.8/ZodError.ts": "528da200fbe995157b9ae91498b103c4ef482217a5c086249507ac850bd78f52", - "https://deno.land/x/zod@v3.23.8/errors.ts": "5285922d2be9700cc0c70c95e4858952b07ae193aa0224be3cbd5cd5567eabef", - "https://deno.land/x/zod@v3.23.8/external.ts": "a6cfbd61e9e097d5f42f8a7ed6f92f93f51ff927d29c9fbaec04f03cbce130fe", - "https://deno.land/x/zod@v3.23.8/helpers/enumUtil.ts": "54efc393cc9860e687d8b81ff52e980def00fa67377ad0bf8b3104f8a5bf698c", - "https://deno.land/x/zod@v3.23.8/helpers/errorUtil.ts": "7a77328240be7b847af6de9189963bd9f79cab32bbc61502a9db4fe6683e2ea7", - "https://deno.land/x/zod@v3.23.8/helpers/parseUtil.ts": "c14814d167cc286972b6e094df88d7d982572a08424b7cd50f862036b6fcaa77", - "https://deno.land/x/zod@v3.23.8/helpers/partialUtil.ts": "998c2fe79795257d4d1cf10361e74492f3b7d852f61057c7c08ac0a46488b7e7", - "https://deno.land/x/zod@v3.23.8/helpers/typeAliases.ts": "0fda31a063c6736fc3cf9090dd94865c811dfff4f3cb8707b932bf937c6f2c3e", - "https://deno.land/x/zod@v3.23.8/helpers/util.ts": "30c273131661ca5dc973f2cfb196fa23caf3a43e224cdde7a683b72e101a31fc", - "https://deno.land/x/zod@v3.23.8/index.ts": "d27aabd973613985574bc31f39e45cb5d856aa122ef094a9f38a463b8ef1a268", - "https://deno.land/x/zod@v3.23.8/locales/en.ts": "a7a25cd23563ccb5e0eed214d9b31846305ddbcdb9c5c8f508b108943366ab4c", - "https://deno.land/x/zod@v3.23.8/mod.ts": "ec6e2b1255c1a350b80188f97bd0a6bac45801bb46fc48f50b9763aa66046039", - "https://deno.land/x/zod@v3.23.8/types.ts": "1b172c90782b1eaa837100ebb6abd726d79d6c1ec336350c8e851e0fd706bf5c", "https://esm.sh/jszip@3.7.1": "f3872a819b015715edb05f81d973b5cd05d3d213d8eb28293ca5471fe7a71773", "https://esm.sh/v135/jszip@3.7.1/denonext/jszip.mjs": "d31d7f9e0de9c6db3c07ca93f7301b756273d4dccb41b600461978fc313504c9", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/deps/cli.ts": "aac025f9372ad413b9c2663dc7f61affd597820d9448f010a510d541df3b56ea", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/deps/common.ts": "f775710b66a9099b98651cd3831906466e9b83ef98f2e5c080fd59ee801c28d4", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/deps/ports.ts": "3c60d1f7ab626ffdd81b37f4e83a780910936480da8fe24f4ccceaefa207d339", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/files/deno/mod.ts": "1b8204c3df18b908408b2148b48af788e669d0debbeb8ba119418ab1ddf1ab8f", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/files/deno/worker.ts": "8ded400d70a0bd40e281ceb1ffcdc82578443caf9c481b9eee77166472784282", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/host/mod.ts": "cc25d1f82e54e6a27eef4571145c3f34c4c8ad9148b3aa48bd3b53d1e078d95d", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/host/types.ts": "f450d9b9c0eced2650262d02455aa6f794de0edd6b052aade256882148e5697f", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/install/mod.ts": "aa54eb3e119f28d33e61645c89669da292ee00376068ead8f45be2807e7a9989", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/install/utils.ts": "d4634d4fc0e963f540402b4ca7eb5dcba340eaa0d8fceb43af57d722ad267115", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/main.ts": "ecd5e83be2d8f351058ad44424cad1f36dd2e3d76f6e8409afc47682a9eff01a", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/modules/envs/inter.ts": "84805fa208754a08f185dca7a5236de3760bbc1d0df96af86ea5fd7778f827a2", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/modules/envs/mod.ts": "5f37b9f155808f8d6d51e1f16f58c07914d8c7d8070bc5c2fb5076ab748798a7", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/modules/envs/posix.ts": "09e410e3fea9c303a5148ff2a22697474320442b9fea0bd3fc932d6828fe820f", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/modules/envs/reducer.ts": "50517084caaf73ce6618141ee4d97795060a0d3169651da7abd7251a3204465a", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/modules/envs/types.ts": "ab9715cf02e9d73f553ae757db347863be23e1e9daf94d18aab716fc27b3dbc1", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/modules/mod.ts": "fc1cb9176c6557b44ae9c6536fa51c6c4f80ac01fc476d15b0a217e70cb0d176", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/modules/ports/ambient.ts": "823ec8d98702a60e6bfcdbeb64b69dc9f5039e73a1f10e87cd51210c1aaf52d5", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/modules/ports/base.ts": "8ef8a8de372420bddcd63a1b363937f43d898059e99478a58621e8432bcd5891", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/modules/ports/db.ts": "a309d1058f66079a481141c3f1733d928b9af8a37b7ce911b1228f70fd24df0f", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/modules/ports/ghrel.ts": "ebbc30a5c31244131d937eadca73fbc099c9e7bdf0ad4f668766d4388ede143c", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/modules/ports/inter.ts": "b3999e73d73d7f928a8de86e5e2261fe6b1450ceedfb54f24537bf0803532ed0", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/modules/ports/mod.ts": "78db7040e724f84c95b1a0fdeaf0cfc53382482e8905cd352189756b953556cc", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/modules/ports/reducers.ts": "d04e813652101f67f946242df68429ed5540e499fbdb7776b8be5703f16754c8", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/modules/ports/sync.ts": "a7a297f6b098360d56af168692f3cff96f8ceeb5189e5baa249e094f8d9c42ef", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/modules/ports/types.ts": "f4dbd1a3f4b7f539b3a85418617d25adbf710b54144161880d48f6c4ec032eee", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/modules/ports/types/platform.ts": "0ecffeda71919293f9ffdb6c564ddea4f23bc85c4e640b08ea78225d34387fdc", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/modules/ports/utils.ts": "6b14b331cce66bd46e7aec51f02424327d819150f16d3f72a6b0aaf7aee43c09", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/modules/ports/worker.ts": "6b76ba1efb2e47a82582fc48bcc6264fe153a166beffccde1a9a3a185024c337", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/modules/std.ts": "419d6b04680f73f7b252257ab287d68c1571cee4347301c53278e2b53df21c4a", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/modules/tasks/deno.ts": "2b9f33253ac1257eb79a4981cd221509aa9ecf8a3c36d7bd8be1cd6c1150100b", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/modules/tasks/exec.ts": "6adcfe13f8d2da5d65331fd1601d4f950d9fc6f164bc9592204e5b08c23c5c30", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/modules/tasks/inter.ts": "63e8f2860f7e3b4d95b6f61ca56aeb8567e4f265aa9c22cace6c8075edd6210f", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/modules/tasks/mod.ts": "334b18d7c110cc05483be96353e342425c0033b7410c271a8a47d2b18308c73e", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/modules/tasks/types.ts": "072a34bd0749428bad4d612cc86abe463d4d4f74dc56cf0a48a1f41650e2399b", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/modules/types.ts": "c0f212b686a2721d076e9aeb127596c7cbc939758e2cc32fd1d165a8fb320a87", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/port.ts": "c039a010dee7dfd978478cf4c5e2256c643135e10f33c30a09f8db9915e9d89d", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/setup_logger.ts": "f8a206bda0595497d6f4718032d4a959000b32ef3346d4b507777eec6a169458", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/utils/logger.ts": "fcbafb35ae4b812412b9b301ce6d06b8b9798f94ebebe3f92677e25e4b19af3c", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/utils/mod.ts": "25bfdd222d6afec5b3f0a7e647e3d9b12abed6d222b49a4b2e95c6bbe266f533", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/utils/unarchive.ts": "f6d0e9e75f470eeef5aecd0089169f4350fc30ebfdc05466bb7b30042294d6d3", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/utils/url.ts": "e1ada6fd30fc796b8918c88456ea1b5bbd87a07d0a0538b092b91fd2bb9b7623", - "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/utils/worker.ts": "ac4caf72a36d2e4af4f4e92f2e0a95f9fc2324b568640f24c7c2ff6dc0c11d62", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/deps/cli.ts": "22fdbfe7f39dc2caa9dd056a57a57051deec6b2a7ba9381e20e2ce7ab6af07e1", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/deps/common.ts": "5d676e006bb1485056935c263a967eee9fcfc1517249d1ca05a7645dca5e2e68", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/deps/ports.ts": "3c60d1f7ab626ffdd81b37f4e83a780910936480da8fe24f4ccceaefa207d339", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/files/deno/mod.ts": "1b8204c3df18b908408b2148b48af788e669d0debbeb8ba119418ab1ddf1ab8f", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/files/deno/worker.ts": "71f3cee9dba3c2bd59c85d2909eac325da556a9917ed6ea01222f6c217638dd9", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/host/mod.ts": "faea10bf051dc22443e0bb3cadb74599d2ef5e4543f065a75777bb57b818c022", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/host/types.ts": "359ceb8a800c5acd9ef4778e40ccfe039fd7724c06205ae3998398641a9b2370", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/install/mod.ts": "f78083efd15e82c8cc302dd801565f39c947497cfaa039fde1023f7e0d5ab368", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/install/utils.ts": "d4634d4fc0e963f540402b4ca7eb5dcba340eaa0d8fceb43af57d722ad267115", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/main.ts": "fb82696926c97ea6749151275cafce049c35c2d500188661ac8b1d205a3b9939", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/modules/envs/mod.ts": "33ddee364795c1f22028e74071063fe85211949682bb94f1ca38396314cbd01e", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/modules/envs/posix.ts": "3193141953de1bfe2d73549e651711f4e1a1d05f5fcc7655ab74160b25be09d0", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/modules/envs/reducer.ts": "853347377f4b265792da2ece78dfde7602c2555341bbd9f8dfd7ac5fd7d989ad", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/modules/envs/types.ts": "a03173fe013a41163471446f41c636bd23acc6e4956ea910e12cb203dc449a9e", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/modules/mod.ts": "fc1cb9176c6557b44ae9c6536fa51c6c4f80ac01fc476d15b0a217e70cb0d176", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/modules/ports/ambient.ts": "823ec8d98702a60e6bfcdbeb64b69dc9f5039e73a1f10e87cd51210c1aaf52d5", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/modules/ports/base.ts": "8ef8a8de372420bddcd63a1b363937f43d898059e99478a58621e8432bcd5891", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/modules/ports/db.ts": "a309d1058f66079a481141c3f1733d928b9af8a37b7ce911b1228f70fd24df0f", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/modules/ports/ghrel.ts": "a1bf0e244080b8b2a62093f536bb7eff0b5a9c596f7eef9f516c11a80aad0be1", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/modules/ports/inter.ts": "62ddc0dede33b059dbd84d18411d0b0acceb145ff96b076401a96c980ae9bfc0", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/modules/ports/mod.ts": "6d4b907ad70a9946299bc5931c976fad1cb1b405466cf4cc8d2acb7d0ba3310c", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/modules/ports/reducers.ts": "eaabbc2cf5d16a55cff5b3f95180f3e1ddb09b1a755776da2931f8817f28a0df", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/modules/ports/sync.ts": "6bbaca38024fd1f6c6ba5811abe65052d2061527539f1893f768ace40016ab5f", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/modules/ports/types.ts": "1adbe5a901f765de106db6513eb770356eed156c435e94d51b7432dce401530e", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/modules/ports/types/platform.ts": "0ecffeda71919293f9ffdb6c564ddea4f23bc85c4e640b08ea78225d34387fdc", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/modules/ports/utils.ts": "6b14b331cce66bd46e7aec51f02424327d819150f16d3f72a6b0aaf7aee43c09", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/modules/ports/worker.ts": "6b76ba1efb2e47a82582fc48bcc6264fe153a166beffccde1a9a3a185024c337", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/modules/std.ts": "419d6b04680f73f7b252257ab287d68c1571cee4347301c53278e2b53df21c4a", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/modules/tasks/deno.ts": "15d5bb6379f3add73cb0d8aa4b578998d87bcfaa939518166c30a7f906ea5750", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/modules/tasks/exec.ts": "cc5db628d85a84b6193f59d7f5d98868f22a59f038716dc3d4fc5ac70494d625", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/modules/tasks/mod.ts": "71a16751895ce8bb687c565602938773ac276ccb62d28a793db0b1715438ee9a", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/modules/tasks/types.ts": "0bf2cf9ac1f5735dc95ac348175866abf602bd90d01c9275c708f767baa976c1", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/modules/types.ts": "53de8906ea0149871e35c937f3e52dee1a615907971fa8ec3f322f4dfe6d40f3", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/modules/utils.ts": "b5866a52cd4e0e1c0dc8ccb56c7281aeff2e2bf5e16866b77eda36e0529e312a", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/port.ts": "c039a010dee7dfd978478cf4c5e2256c643135e10f33c30a09f8db9915e9d89d", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/setup_logger.ts": "f8a206bda0595497d6f4718032d4a959000b32ef3346d4b507777eec6a169458", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/utils/logger.ts": "fcbafb35ae4b812412b9b301ce6d06b8b9798f94ebebe3f92677e25e4b19af3c", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/utils/mod.ts": "d4d0c0198168f63bd084872bf7dfb40925301ecb65fd0501520db942f6c0c961", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/utils/unarchive.ts": "f6d0e9e75f470eeef5aecd0089169f4350fc30ebfdc05466bb7b30042294d6d3", - "https://raw.githubusercontent.com/metatypedev/ghjk/0c5f78/utils/url.ts": "e1ada6fd30fc796b8918c88456ea1b5bbd87a07d0a0538b092b91fd2bb9b7623", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/deps/cli.ts": "aac025f9372ad413b9c2663dc7f61affd597820d9448f010a510d541df3b56ea", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/deps/common.ts": "f775710b66a9099b98651cd3831906466e9b83ef98f2e5c080fd59ee801c28d4", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/deps/ports.ts": "3c60d1f7ab626ffdd81b37f4e83a780910936480da8fe24f4ccceaefa207d339", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/files/deno/mod.ts": "1b8204c3df18b908408b2148b48af788e669d0debbeb8ba119418ab1ddf1ab8f", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/files/deno/worker.ts": "8ded400d70a0bd40e281ceb1ffcdc82578443caf9c481b9eee77166472784282", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/host/mod.ts": "604e2729145c16226af91e6880e3eca30ea060688fb4941ab39d9489109dd62c", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/host/types.ts": "f450d9b9c0eced2650262d02455aa6f794de0edd6b052aade256882148e5697f", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/install/mod.ts": "f78083efd15e82c8cc302dd801565f39c947497cfaa039fde1023f7e0d5ab368", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/install/utils.ts": "d4634d4fc0e963f540402b4ca7eb5dcba340eaa0d8fceb43af57d722ad267115", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/main.ts": "21ea4582db19e163f4dd68ccdb19578c3c48e48dd23c094d8f8f88ab785e34e5", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/modules/envs/inter.ts": "84805fa208754a08f185dca7a5236de3760bbc1d0df96af86ea5fd7778f827a2", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/modules/envs/mod.ts": "b9483be6dbd4c282d1c5b134864b2ff0f53d8bfb25dba6c96e591c84ccf25e01", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/modules/envs/posix.ts": "09e410e3fea9c303a5148ff2a22697474320442b9fea0bd3fc932d6828fe820f", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/modules/envs/reducer.ts": "853347377f4b265792da2ece78dfde7602c2555341bbd9f8dfd7ac5fd7d989ad", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/modules/envs/types.ts": "ab9715cf02e9d73f553ae757db347863be23e1e9daf94d18aab716fc27b3dbc1", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/modules/mod.ts": "fc1cb9176c6557b44ae9c6536fa51c6c4f80ac01fc476d15b0a217e70cb0d176", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/modules/ports/ambient.ts": "823ec8d98702a60e6bfcdbeb64b69dc9f5039e73a1f10e87cd51210c1aaf52d5", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/modules/ports/base.ts": "8ef8a8de372420bddcd63a1b363937f43d898059e99478a58621e8432bcd5891", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/modules/ports/db.ts": "a309d1058f66079a481141c3f1733d928b9af8a37b7ce911b1228f70fd24df0f", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/modules/ports/ghrel.ts": "a1bf0e244080b8b2a62093f536bb7eff0b5a9c596f7eef9f516c11a80aad0be1", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/modules/ports/inter.ts": "b3999e73d73d7f928a8de86e5e2261fe6b1450ceedfb54f24537bf0803532ed0", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/modules/ports/mod.ts": "2b5d4773d64641cdc0aacf09ece6c40d094feb090280647c68f33bbfa8dceee7", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/modules/ports/reducers.ts": "eaabbc2cf5d16a55cff5b3f95180f3e1ddb09b1a755776da2931f8817f28a0df", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/modules/ports/sync.ts": "a7a297f6b098360d56af168692f3cff96f8ceeb5189e5baa249e094f8d9c42ef", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/modules/ports/types.ts": "f4dbd1a3f4b7f539b3a85418617d25adbf710b54144161880d48f6c4ec032eee", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/modules/ports/types/platform.ts": "0ecffeda71919293f9ffdb6c564ddea4f23bc85c4e640b08ea78225d34387fdc", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/modules/ports/utils.ts": "6b14b331cce66bd46e7aec51f02424327d819150f16d3f72a6b0aaf7aee43c09", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/modules/ports/worker.ts": "6b76ba1efb2e47a82582fc48bcc6264fe153a166beffccde1a9a3a185024c337", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/modules/std.ts": "419d6b04680f73f7b252257ab287d68c1571cee4347301c53278e2b53df21c4a", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/modules/tasks/deno.ts": "2b9f33253ac1257eb79a4981cd221509aa9ecf8a3c36d7bd8be1cd6c1150100b", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/modules/tasks/exec.ts": "eaf6b2f9639185fa76f560276e0d28d262a6c78d2bdc0d579e7683e062d7b542", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/modules/tasks/inter.ts": "63e8f2860f7e3b4d95b6f61ca56aeb8567e4f265aa9c22cace6c8075edd6210f", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/modules/tasks/mod.ts": "438f1cbb5e96470f380b6954bb18ad7693ed33bb99314137ff7080d82d026615", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/modules/tasks/types.ts": "072a34bd0749428bad4d612cc86abe463d4d4f74dc56cf0a48a1f41650e2399b", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/modules/types.ts": "c0f212b686a2721d076e9aeb127596c7cbc939758e2cc32fd1d165a8fb320a87", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/port.ts": "c039a010dee7dfd978478cf4c5e2256c643135e10f33c30a09f8db9915e9d89d", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/setup_logger.ts": "f8a206bda0595497d6f4718032d4a959000b32ef3346d4b507777eec6a169458", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/utils/logger.ts": "fcbafb35ae4b812412b9b301ce6d06b8b9798f94ebebe3f92677e25e4b19af3c", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/utils/mod.ts": "fe8b14465fbcbf3a952af48083a17304c294f296591752dff3ca141386c2d46b", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/utils/unarchive.ts": "f6d0e9e75f470eeef5aecd0089169f4350fc30ebfdc05466bb7b30042294d6d3", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/utils/url.ts": "e1ada6fd30fc796b8918c88456ea1b5bbd87a07d0a0538b092b91fd2bb9b7623", - "https://raw.githubusercontent.com/metatypedev/ghjk/5bb0d24/utils/worker.ts": "ac4caf72a36d2e4af4f4e92f2e0a95f9fc2324b568640f24c7c2ff6dc0c11d62" + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/deps/cli.ts": "aac025f9372ad413b9c2663dc7f61affd597820d9448f010a510d541df3b56ea", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/deps/common.ts": "f775710b66a9099b98651cd3831906466e9b83ef98f2e5c080fd59ee801c28d4", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/deps/ports.ts": "3c60d1f7ab626ffdd81b37f4e83a780910936480da8fe24f4ccceaefa207d339", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/files/deno/mod.ts": "1b8204c3df18b908408b2148b48af788e669d0debbeb8ba119418ab1ddf1ab8f", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/files/deno/worker.ts": "8ded400d70a0bd40e281ceb1ffcdc82578443caf9c481b9eee77166472784282", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/host/mod.ts": "af5a9704c3a5b410b322afe0bc8caaaac5b28e1e1591d82b0c5fb53f92cbc97f", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/host/types.ts": "f450d9b9c0eced2650262d02455aa6f794de0edd6b052aade256882148e5697f", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/install/mod.ts": "aa54eb3e119f28d33e61645c89669da292ee00376068ead8f45be2807e7a9989", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/install/utils.ts": "d4634d4fc0e963f540402b4ca7eb5dcba340eaa0d8fceb43af57d722ad267115", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/main.ts": "ecd5e83be2d8f351058ad44424cad1f36dd2e3d76f6e8409afc47682a9eff01a", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/envs/inter.ts": "84805fa208754a08f185dca7a5236de3760bbc1d0df96af86ea5fd7778f827a2", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/envs/mod.ts": "5f37b9f155808f8d6d51e1f16f58c07914d8c7d8070bc5c2fb5076ab748798a7", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/envs/posix.ts": "b22f9564d9773548d537c95265e694a2630c3fe1fd63354d6f4790e275545299", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/envs/reducer.ts": "76ee6974c9d4885da0898e01c498dcfdd99a3652a5a564d679577931a680e781", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/envs/types.ts": "9ff28d47aa60042df42fbb98a46f7689d8111be462237f5fb81771011e429088", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/mod.ts": "fc1cb9176c6557b44ae9c6536fa51c6c4f80ac01fc476d15b0a217e70cb0d176", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/ports/ambient.ts": "823ec8d98702a60e6bfcdbeb64b69dc9f5039e73a1f10e87cd51210c1aaf52d5", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/ports/base.ts": "8ef8a8de372420bddcd63a1b363937f43d898059e99478a58621e8432bcd5891", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/ports/db.ts": "a309d1058f66079a481141c3f1733d928b9af8a37b7ce911b1228f70fd24df0f", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/ports/ghrel.ts": "ebbc30a5c31244131d937eadca73fbc099c9e7bdf0ad4f668766d4388ede143c", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/ports/inter.ts": "b3999e73d73d7f928a8de86e5e2261fe6b1450ceedfb54f24537bf0803532ed0", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/ports/mod.ts": "646cfe12c181f378ffd865890e07ba0a2c92b70cf10687f43de49864ca15c482", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/ports/reducers.ts": "d04e813652101f67f946242df68429ed5540e499fbdb7776b8be5703f16754c8", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/ports/sync.ts": "a7a297f6b098360d56af168692f3cff96f8ceeb5189e5baa249e094f8d9c42ef", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/ports/types.ts": "f4dbd1a3f4b7f539b3a85418617d25adbf710b54144161880d48f6c4ec032eee", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/ports/types/platform.ts": "0ecffeda71919293f9ffdb6c564ddea4f23bc85c4e640b08ea78225d34387fdc", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/ports/utils.ts": "6b14b331cce66bd46e7aec51f02424327d819150f16d3f72a6b0aaf7aee43c09", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/ports/worker.ts": "6b76ba1efb2e47a82582fc48bcc6264fe153a166beffccde1a9a3a185024c337", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/std.ts": "419d6b04680f73f7b252257ab287d68c1571cee4347301c53278e2b53df21c4a", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/tasks/deno.ts": "75b85d8cdc129e56d7bd1bfbfdc4a6f4685e86933c41908e48fbc51be7a57fee", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/tasks/exec.ts": "ddc6bc7cbed464fdd94038a0df8668138411e94e49ae639615b93e734e37d311", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/tasks/inter.ts": "63e8f2860f7e3b4d95b6f61ca56aeb8567e4f265aa9c22cace6c8075edd6210f", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/tasks/mod.ts": "334b18d7c110cc05483be96353e342425c0033b7410c271a8a47d2b18308c73e", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/tasks/types.ts": "072a34bd0749428bad4d612cc86abe463d4d4f74dc56cf0a48a1f41650e2399b", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/types.ts": "c0f212b686a2721d076e9aeb127596c7cbc939758e2cc32fd1d165a8fb320a87", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/port.ts": "c039a010dee7dfd978478cf4c5e2256c643135e10f33c30a09f8db9915e9d89d", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/ports/act.ts": "2ce6b8fddf61db12ba69b7cad6985237a2962ca79853edbddee5bfb49c47d1ab", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/ports/deno_ghrel.ts": "eca02a93ceb62ad9fb7f395361d32da0d5657aba5f7856c8ae0109135da0e070", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/setup_logger.ts": "f8a206bda0595497d6f4718032d4a959000b32ef3346d4b507777eec6a169458", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/utils/logger.ts": "fcbafb35ae4b812412b9b301ce6d06b8b9798f94ebebe3f92677e25e4b19af3c", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/utils/mod.ts": "25901b5a03625353cc0d9c024daca806eb2513b153faede5ecad73b428542721", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/utils/unarchive.ts": "f6d0e9e75f470eeef5aecd0089169f4350fc30ebfdc05466bb7b30042294d6d3", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/utils/url.ts": "e1ada6fd30fc796b8918c88456ea1b5bbd87a07d0a0538b092b91fd2bb9b7623", + "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/utils/worker.ts": "ac4caf72a36d2e4af4f4e92f2e0a95f9fc2324b568640f24c7c2ff6dc0c11d62" } } diff --git a/.ghjk/lock.json b/.ghjk/lock.json index cad9504a..32181f40 100644 --- a/.ghjk/lock.json +++ b/.ghjk/lock.json @@ -1,85 +1,300 @@ { "version": "0", - "platform": "aarch64-darwin", - "moduleEntries": { + "sys_entries": { "ports": { "version": "0", "configResolutions": { + "bciqeosxosr6ur7pu7gny33gy7dqubmxbcs4775xazb4zvaxavkd5rha": { + "version": "0.1.13", + "buildDepConfigs": { + "cargo_binstall_ghrel": { + "version": "v1.10.18", + "buildDepConfigs": {}, + "portRef": "cargo_binstall_ghrel@0.1.0", + "specifiedVersion": false + }, + "rust_rustup": { + "version": "1.82.0", + "buildDepConfigs": { + "rustup_rustlang": { + "version": "1.27.1", + "buildDepConfigs": { + "git_aa": { + "version": "2.47.1", + "buildDepConfigs": {}, + "portRef": "git_aa@0.1.0", + "specifiedVersion": false + } + }, + "portRef": "rustup_rustlang@0.1.0", + "specifiedVersion": false + } + }, + "portRef": "rust_rustup@0.1.0", + "profile": "default", + "components": [ + "rust-src" + ], + "specifiedVersion": true + } + }, + "portRef": "cargobi_cratesio@0.1.0", + "crateName": "tokio-console", + "specifiedVersion": false + }, + "bciqeal5okt5zj763vhgsmf3afr5thrkqaitv6pb3wwegcwyb74gdyjq": { + "version": "v1.10.18", + "buildDepConfigs": {}, + "portRef": "cargo_binstall_ghrel@0.1.0", + "specifiedVersion": false + }, + "bciqar6zz2xgxmu5i2jp5nuj4wsogcl7pxsqs3w55mibcsbks5iimsyy": { + "version": "1.82.0", + "buildDepConfigs": { + "rustup_rustlang": { + "version": "1.27.1", + "buildDepConfigs": { + "git_aa": { + "version": "2.47.1", + "buildDepConfigs": {}, + "portRef": "git_aa@0.1.0", + "specifiedVersion": false + } + }, + "portRef": "rustup_rustlang@0.1.0", + "specifiedVersion": false + } + }, + "portRef": "rust_rustup@0.1.0", + "profile": "default", + "components": [ + "rust-src" + ], + "specifiedVersion": true + }, "bciqay4m4kmzfduj5t2clgejxgpe5zwper6lyyaxt7rhbjalaqd32nhq": { - "version": "2.34.1", + "version": "2.47.1", "buildDepConfigs": {}, "portRef": "git_aa@0.1.0", "specifiedVersion": false }, - "bciqjlw6cxddajjmznoemlmnu7mgbbm7a3hfmnd2x5oivwajmiqui5ey": { - "version": "v0.2.64", + "bciqewpyjyfnnk4rbd6bbu5who2w6ve7dyt3inal72zg23cs4qnln32q": { + "version": "1.27.1", + "buildDepConfigs": { + "git_aa": { + "version": "2.47.1", + "buildDepConfigs": {}, + "portRef": "git_aa@0.1.0", + "specifiedVersion": false + } + }, + "portRef": "rustup_rustlang@0.1.0", + "specifiedVersion": false + }, + "bciqkv7foyoio4wpti4yf2qrw5nphkgk2din6ba7mjv2w7hmgrv725ja": { + "version": "v2.4.0", + "buildDepConfigs": { + "tar_aa": { + "version": "1.35", + "buildDepConfigs": {}, + "portRef": "tar_aa@0.1.0", + "specifiedVersion": false + } + }, + "portRef": "mold_ghrel@0.1.0", + "replaceLd": true, + "specifiedVersion": true + }, + "bciqj4p5hoqweghbuvz52rupja7sqze34z63dd62nz632c5zxikv6ezy": { + "version": "1.35", "buildDepConfigs": {}, - "portRef": "act_ghrel@0.1.0", + "portRef": "tar_aa@0.1.0", "specifiedVersion": false }, - "bciqao2s3r3r33ruox4qknfrxqrmemuccxn64dze2ylojrzp2bwvt4ji": { - "version": "3.7.1", + "bciqkpfuyqchouu5o3whigod3f5coscq2jdlwde6fztypy3x6fg6xb5q": { + "version": "v29.2", + "buildDepConfigs": {}, + "portRef": "protoc_ghrel@0.1.0", + "specifiedVersion": false + }, + "bciqe6tpdv6hffdbc7hql52w3ivpdls47lgpuhsa3hzsryrwx7ty5dgy": { + "version": "3.31.2", "buildDepConfigs": { "cpy_bs_ghrel": { - "version": "3.12.4", + "version": "3.13.1", "buildDepConfigs": { "tar_aa": { - "version": "1.34", + "version": "1.35", "buildDepConfigs": {}, "portRef": "tar_aa@0.1.0", "specifiedVersion": false }, "zstd_aa": { - "version": "v1.4.8,", + "version": "v1.5.6", "buildDepConfigs": {}, "portRef": "zstd_aa@0.1.0", "specifiedVersion": false } }, "portRef": "cpy_bs_ghrel@0.1.0", - "specifiedVersion": false + "specifiedVersion": true } }, "portRef": "pipi_pypi@0.1.0", - "packageName": "pre-commit", + "packageName": "cmake", "specifiedVersion": false }, - "bciqij3g6mmbjn4a6ps4eipcy2fmw2zumgv5a3gbxycthroffihwquoi": { - "version": "3.12.4", + "bciqicl4snbxiu6ikns3zjrriwo3qpo4dv3ooxjkwnr35utnqshubdcq": { + "version": "3.13.1", "buildDepConfigs": { "tar_aa": { - "version": "1.34", + "version": "1.35", "buildDepConfigs": {}, "portRef": "tar_aa@0.1.0", "specifiedVersion": false }, "zstd_aa": { - "version": "v1.4.8,", + "version": "v1.5.6", "buildDepConfigs": {}, "portRef": "zstd_aa@0.1.0", "specifiedVersion": false } }, "portRef": "cpy_bs_ghrel@0.1.0", - "specifiedVersion": false + "specifiedVersion": true }, - "bciqj4p5hoqweghbuvz52rupja7sqze34z63dd62nz632c5zxikv6ezy": { - "version": "1.34", + "bciqe6fwheayositrdk7rkr2ngdr4wizldakex23tgivss7w6z7g3q3y": { + "version": "v1.5.6", "buildDepConfigs": {}, - "portRef": "tar_aa@0.1.0", + "portRef": "zstd_aa@0.1.0", "specifiedVersion": false }, - "bciqe6fwheayositrdk7rkr2ngdr4wizldakex23tgivss7w6z7g3q3y": { - "version": "v1.4.8,", + "bciqjlw6cxddajjmznoemlmnu7mgbbm7a3hfmnd2x5oivwajmiqui5ey": { + "version": "v0.2.71", "buildDepConfigs": {}, - "portRef": "zstd_aa@0.1.0", + "portRef": "act_ghrel@0.1.0", + "specifiedVersion": false + }, + "bciqao2s3r3r33ruox4qknfrxqrmemuccxn64dze2ylojrzp2bwvt4ji": { + "version": "4.0.1", + "buildDepConfigs": { + "cpy_bs_ghrel": { + "version": "3.13.1", + "buildDepConfigs": { + "tar_aa": { + "version": "1.35", + "buildDepConfigs": {}, + "portRef": "tar_aa@0.1.0", + "specifiedVersion": false + }, + "zstd_aa": { + "version": "v1.5.6", + "buildDepConfigs": {}, + "portRef": "zstd_aa@0.1.0", + "specifiedVersion": false + } + }, + "portRef": "cpy_bs_ghrel@0.1.0", + "specifiedVersion": true + } + }, + "portRef": "pipi_pypi@0.1.0", + "packageName": "pre-commit", "specifiedVersion": false }, - "bciqfvlwwndlfuqibybkgee3fgt7cst5ltpztmm3by6hib5veial5spy": { - "version": "v1.44.2", + "bciqoawx3omfmmhaw25mgrujoxl5wkdwfzbmidfqah2zst7cildtcpeq": { + "version": "3.9.1.0", + "buildDepConfigs": { + "cpy_bs_ghrel": { + "version": "3.13.1", + "buildDepConfigs": { + "tar_aa": { + "version": "1.35", + "buildDepConfigs": {}, + "portRef": "tar_aa@0.1.0", + "specifiedVersion": false + }, + "zstd_aa": { + "version": "v1.5.6", + "buildDepConfigs": {}, + "portRef": "zstd_aa@0.1.0", + "specifiedVersion": false + } + }, + "portRef": "cpy_bs_ghrel@0.1.0", + "specifiedVersion": true + } + }, + "portRef": "pipi_pypi@0.1.0", + "packageName": "vale", + "specifiedVersion": false + }, + "bciqe7g5m4v5jkg3ubqhogjjntsduyrwxcirqcp6tc3jmjr5af7ojq6a": { + "version": "v2.1.2", "buildDepConfigs": {}, "portRef": "deno_ghrel@0.1.0", "specifiedVersion": true + }, + "bciqmpujkkyxmzdz7sxpvi2pmajzfmg6gofplyqn43av2styxu2ng7sy": { + "version": "8.9.1", + "buildDepConfigs": {}, + "portRef": "curl_aa@0.1.0", + "specifiedVersion": false + }, + "bciqldq3d5ozrnh64liohwl5epkckja37mokbbjiddhsco6yh2n2ppda": { + "version": "1.7.1", + "buildDepConfigs": { + "curl_aa": { + "version": "8.9.1", + "buildDepConfigs": {}, + "portRef": "curl_aa@0.1.0", + "specifiedVersion": false + }, + "git_aa": { + "version": "2.47.1", + "buildDepConfigs": {}, + "portRef": "git_aa@0.1.0", + "specifiedVersion": false + }, + "asdf_plugin_git": { + "version": "addae51180", + "buildDepConfigs": { + "git_aa": { + "version": "2.47.1", + "buildDepConfigs": {}, + "portRef": "git_aa@0.1.0", + "specifiedVersion": false + } + }, + "portRef": "asdf_plugin_git@0.1.0", + "pluginRepo": "https://github.com/lsanwick/asdf-jq", + "specifiedVersion": false + } + }, + "resolutionDepConfigs": { + "asdf_plugin_git": { + "pluginRepo": "https://github.com/lsanwick/asdf-jq", + "portRef": "asdf_plugin_git@0.1.0" + } + }, + "portRef": "asdf@0.1.0", + "pluginRepo": "https://github.com/lsanwick/asdf-jq", + "installType": "version", + "specifiedVersion": false + }, + "bciqjatixpjgnlwlrdxmz2r5g2werxjkkvs4wsw4c57fbipdza4qexua": { + "version": "addae51180", + "buildDepConfigs": { + "git_aa": { + "version": "2.47.1", + "buildDepConfigs": {}, + "portRef": "git_aa@0.1.0", + "specifiedVersion": false + } + }, + "portRef": "asdf_plugin_git@0.1.0", + "pluginRepo": "https://github.com/lsanwick/asdf-jq", + "specifiedVersion": false } } }, @@ -98,16 +313,45 @@ "sets": { "ghjkEnvProvInstSet___main": { "installs": [ + "bciqjucge6yrzcawqzcljvrpmtwrocecsww6pcjwipzn5j2hfwjof7za", + "bciqe72molvtvcuj3tuh47ziue2oqd6t4qetxn3rsoa764ofup6uwjmi", + "bciqe4zlekl4uqqbhxunac7br24mrf6cdpfrfblahqa4vrgaqjujcl4i", + "bciqpu4klxr3hl6ujhmflrlfd3dxp47ijq26mnathb26ojzwkeggy5ii", + "bciqelae2kzmf7umbo62flzq2mnlhnc4ilbfmn4va2fzrqwx7w7zusji" + ], + "allowedBuildDeps": "bciqdg64uhkvlkqyc7nli33cja3aolbcdr75qepnrhj5ojlifsvxqzgq" + }, + "ghjkEnvProvInstSet____rust": { + "installs": [ + "bciqikjfnbntvagpghawbzlfp2es6lnqzhba3qx5de7tdrmvhuzhsjqa", + "bciqfrfun7z7soj7yxzziyvmt2jnebqvneeoozk5vynmg5pa6wqynhvi", + "bciqgkc6fegmxehj4whmusfuurxyp4ayeysn6qa2t6q64baac5is7uui", + "bciqjucge6yrzcawqzcljvrpmtwrocecsww6pcjwipzn5j2hfwjof7za", "bciqe72molvtvcuj3tuh47ziue2oqd6t4qetxn3rsoa764ofup6uwjmi", "bciqe4zlekl4uqqbhxunac7br24mrf6cdpfrfblahqa4vrgaqjujcl4i", - "bciqjyl5um6634zwpw6cewv22chzlrsvhedbjahyghhy2zraqqgyiv2q", - "bciqmgggy7hd5as3zz7pzbx54va7lq657bdxvthntxphhlbsl2434dgq" + "bciqpu4klxr3hl6ujhmflrlfd3dxp47ijq26mnathb26ojzwkeggy5ii", + "bciqelae2kzmf7umbo62flzq2mnlhnc4ilbfmn4va2fzrqwx7w7zusji" ], - "allowedBuildDeps": "bciqjx7llw7t6pfczypzmhbwv7sxaicruj5pdbuac47m4c5qyildiowi" + "allowedBuildDeps": "bciqdg64uhkvlkqyc7nli33cja3aolbcdr75qepnrhj5ojlifsvxqzgq" }, - "ghjkEnvProvInstSet___test": { + "ghjkEnvProvInstSet___dev": { + "installs": [ + "bciqlfx3mm5hi37g75snjknph6fkniixjhnvyyfxeua7f5z4h7nnqtna", + "bciqlmoqot4jk2lb2b34pldr5iiwsfm3biuipzesjkkwmc2n2o6nlw4q", + "bciqikjfnbntvagpghawbzlfp2es6lnqzhba3qx5de7tdrmvhuzhsjqa", + "bciqfrfun7z7soj7yxzziyvmt2jnebqvneeoozk5vynmg5pa6wqynhvi", + "bciqgkc6fegmxehj4whmusfuurxyp4ayeysn6qa2t6q64baac5is7uui", + "bciqjucge6yrzcawqzcljvrpmtwrocecsww6pcjwipzn5j2hfwjof7za", + "bciqe72molvtvcuj3tuh47ziue2oqd6t4qetxn3rsoa764ofup6uwjmi", + "bciqe4zlekl4uqqbhxunac7br24mrf6cdpfrfblahqa4vrgaqjujcl4i", + "bciqpu4klxr3hl6ujhmflrlfd3dxp47ijq26mnathb26ojzwkeggy5ii", + "bciqelae2kzmf7umbo62flzq2mnlhnc4ilbfmn4va2fzrqwx7w7zusji" + ], + "allowedBuildDeps": "bciqdg64uhkvlkqyc7nli33cja3aolbcdr75qepnrhj5ojlifsvxqzgq" + }, + "ghjkEnvProvInstSet_______task_env_cache-v8": { "installs": [], - "allowedBuildDeps": "bciqjx7llw7t6pfczypzmhbwv7sxaicruj5pdbuac47m4c5qyildiowi" + "allowedBuildDeps": "bciqeie3punk3gz4kcfdk2fxx5bsj5fh3j7bb7z36qmimayhwdsvp7cq" } } } @@ -119,11 +363,18 @@ "lock-sed": { "ty": "denoFile@v1", "key": "lock-sed", - "envKey": "bciqekhy7ndyc6hmkzspdsguxjgvyz5yedr5weigsqsa72kyloity4jy" + "envKey": "bciqocjamyeiuh6llwcdqg4q4ceantuzpbm5bmnlz7pkqz4r2ca7w2eq" + }, + "cache-v8": { + "ty": "denoFile@v1", + "key": "cache-v8", + "desc": "Install the V8 builds to a local cache.", + "envKey": "bciqngtgh6vxbmug3jgfhtc6t2o7d4375gzfwxca2hmq2mhwbe4tajvq" } }, "tasksNamed": [ - "lock-sed" + "lock-sed", + "cache-v8" ] } }, @@ -131,32 +382,133 @@ "id": "envs", "config": { "envs": { - "bciqekhy7ndyc6hmkzspdsguxjgvyz5yedr5weigsqsa72kyloity4jy": { + "bciqngtgh6vxbmug3jgfhtc6t2o7d4375gzfwxca2hmq2mhwbe4tajvq": { "provides": [ { "ty": "ghjk.ports.InstallSetRef", - "setId": "ghjkEnvProvInstSet___test" + "setId": "ghjkEnvProvInstSet_______task_env_cache-v8" } ] }, - "bciqfzekhtsrjd72noxifmici3ssck4jgvbjwhxwhhwtirzm7yomhxya": { + "bciqfnku2tswsz4gapwhys5ox5uiyzcb5r7bmuwzljjeziljcu7efroi": { "desc": "the default default environment.", "provides": [ + { + "ty": "posix.envVar", + "key": "RUST_LOG", + "val": "info,deno::npm=info,deno::file_fetcher=info,swc_ecma_transforms_base=info,swc_common=info,h2=info,rustls=info,mio=info,hyper_util=info" + }, + { + "ty": "ghjk.ports.InstallSetRef", + "setId": "ghjkEnvProvInstSet___main" + } + ] + }, + "bciqocjamyeiuh6llwcdqg4q4ceantuzpbm5bmnlz7pkqz4r2ca7w2eq": { + "provides": [ + { + "ty": "posix.envVar", + "key": "RUST_LOG", + "val": "info,deno::npm=info,deno::file_fetcher=info,swc_ecma_transforms_base=info,swc_common=info,h2=info,rustls=info,mio=info,hyper_util=info" + }, { "ty": "ghjk.ports.InstallSetRef", "setId": "ghjkEnvProvInstSet___main" } ] + }, + "bciqex5g2cetqvfipwhu6fb3mmyke3y6jvrscjrykf2zl7wfwupiqhca": { + "provides": [ + { + "ty": "posix.envVar", + "key": "RUST_LOG", + "val": "info,deno::npm=info,deno::file_fetcher=info,swc_ecma_transforms_base=info,swc_common=info,h2=info,rustls=info,mio=info,hyper_util=info" + }, + { + "ty": "ghjk.ports.InstallSetRef", + "setId": "ghjkEnvProvInstSet____rust" + } + ] + }, + "bciqgcwltl3sbuyrqlhxz2spihe2asdzrgt3axosw3mre7ived23syhy": { + "provides": [ + { + "ty": "posix.envVar", + "key": "RUST_LOG", + "val": "info,deno::npm=info,deno::file_fetcher=info,swc_ecma_transforms_base=info,swc_common=info,h2=info,rustls=info,mio=info,hyper_util=info" + }, + { + "ty": "posix.envVar", + "key": "RUSTY_V8_MIRROR", + "val": "/var/home/asdf/repos/ecma/ghjk/.dev/rusty_v8" + }, + { + "ty": "ghjk.ports.InstallSetRef", + "setId": "ghjkEnvProvInstSet___dev" + } + ] } }, - "defaultEnv": "main", + "defaultEnv": "dev", "envsNamed": { - "main": "bciqfzekhtsrjd72noxifmici3ssck4jgvbjwhxwhhwtirzm7yomhxya" + "main": "bciqfnku2tswsz4gapwhys5ox5uiyzcb5r7bmuwzljjeziljcu7efroi", + "_rust": "bciqex5g2cetqvfipwhu6fb3mmyke3y6jvrscjrykf2zl7wfwupiqhca", + "dev": "bciqgcwltl3sbuyrqlhxz2spihe2asdzrgt3axosw3mre7ived23syhy" } } } ], "blackboard": { + "bciqjucge6yrzcawqzcljvrpmtwrocecsww6pcjwipzn5j2hfwjof7za": { + "buildDepConfigs": { + "asdf_plugin_git": { + "pluginRepo": "https://github.com/lsanwick/asdf-jq", + "portRef": "asdf_plugin_git@0.1.0" + } + }, + "resolutionDepConfigs": { + "asdf_plugin_git": { + "pluginRepo": "https://github.com/lsanwick/asdf-jq", + "portRef": "asdf_plugin_git@0.1.0" + } + }, + "port": { + "ty": "denoWorker@v1", + "name": "asdf", + "platforms": [ + "x86_64-linux", + "aarch64-linux", + "x86_64-darwin", + "aarch64-darwin" + ], + "version": "0.1.0", + "buildDeps": [ + { + "name": "curl_aa" + }, + { + "name": "git_aa" + }, + { + "name": "asdf_plugin_git" + } + ], + "resolutionDeps": [ + { + "name": "curl_aa" + }, + { + "name": "git_aa" + }, + { + "name": "asdf_plugin_git" + } + ], + "moduleSpecifier": "file:///ports/asdf.ts" + }, + "pluginRepo": "https://github.com/lsanwick/asdf-jq", + "installType": "version" + }, "bciqe72molvtvcuj3tuh47ziue2oqd6t4qetxn3rsoa764ofup6uwjmi": { "port": { "ty": "denoWorker@v1", @@ -207,8 +559,59 @@ }, "packageName": "pre-commit" }, - "bciqjyl5um6634zwpw6cewv22chzlrsvhedbjahyghhy2zraqqgyiv2q": { + "bciqpu4klxr3hl6ujhmflrlfd3dxp47ijq26mnathb26ojzwkeggy5ii": { + "port": { + "ty": "denoWorker@v1", + "name": "pipi_pypi", + "platforms": [ + "x86_64-linux", + "aarch64-linux", + "x86_64-darwin", + "aarch64-darwin", + "x86_64-windows", + "aarch64-windows", + "x86_64-freebsd", + "aarch64-freebsd", + "x86_64-netbsd", + "aarch64-netbsd", + "x86_64-aix", + "aarch64-aix", + "x86_64-solaris", + "aarch64-solaris", + "x86_64-illumos", + "aarch64-illumos", + "x86_64-android", + "aarch64-android" + ], + "version": "0.1.0", + "buildDeps": [ + { + "name": "cpy_bs_ghrel" + } + ], + "moduleSpecifier": "file:///ports/pipi.ts" + }, + "packageName": "vale" + }, + "bciqelae2kzmf7umbo62flzq2mnlhnc4ilbfmn4va2fzrqwx7w7zusji": { + "version": "2.1.2", "port": { + "ty": "denoWorker@v1", + "name": "deno_ghrel", + "platforms": [ + "aarch64-linux", + "x86_64-linux", + "aarch64-darwin", + "x86_64-darwin", + "aarch64-windows", + "x86_64-windows" + ], + "version": "0.1.0", + "moduleSpecifier": "file:///ports/deno_ghrel.ts" + } + }, + "bciqdfarczmlu3r5dkvcdoultfbnuvn6saao55h4fbb3jg72kv6mkr3y": { + "manifest": { "ty": "denoWorker@v1", "name": "cpy_bs_ghrel", "platforms": [ @@ -229,23 +632,51 @@ } ], "moduleSpecifier": "file:///ports/cpy_bs.ts" + }, + "defaultInst": { + "version": "3.13.1", + "portRef": "cpy_bs_ghrel@0.1.0" } }, - "bciqmgggy7hd5as3zz7pzbx54va7lq657bdxvthntxphhlbsl2434dgq": { - "version": "1.44.2", - "port": { + "bciqgze4knhjfbiypt5axkjslfsduq6tbwszbiuy5zsgpacrm5h6cg4a": { + "manifest": { "ty": "denoWorker@v1", - "name": "deno_ghrel", + "name": "rust_rustup", "platforms": [ - "aarch64-linux", "x86_64-linux", - "aarch64-darwin", + "aarch64-linux", "x86_64-darwin", + "aarch64-darwin", + "x86_64-windows", "aarch64-windows", - "x86_64-windows" + "x86_64-freebsd", + "aarch64-freebsd", + "x86_64-netbsd", + "aarch64-netbsd", + "x86_64-aix", + "aarch64-aix", + "x86_64-solaris", + "aarch64-solaris", + "x86_64-illumos", + "aarch64-illumos", + "x86_64-android", + "aarch64-android" ], "version": "0.1.0", - "moduleSpecifier": "file:///ports/deno_ghrel.ts" + "buildDeps": [ + { + "name": "rustup_rustlang" + } + ], + "moduleSpecifier": "file:///ports/rust.ts" + }, + "defaultInst": { + "version": "1.82.0", + "portRef": "rust_rustup@0.1.0", + "profile": "default", + "components": [ + "rust-src" + ] } }, "bciqb6ua63xodzwxngnbjq35hfikiwzb3dclbqkc7e6xgjdt5jin4pia": { @@ -358,7 +789,7 @@ "portRef": "unzip_aa@0.1.0" } }, - "bciqmcvyepuficjj3mwshsbfecwdmzch5gwxqo557icnq4zujtdllh4a": { + "bciqpezvwy56igv7hqdpb3qreewqmyftjyej7zhcyhz6afcgfxgy3rjy": { "manifest": { "ty": "ambientAccess@v1", "name": "zstd_aa", @@ -371,7 +802,7 @@ "version": "0.1.0", "execName": "zstd", "versionExtractFlag": "--version", - "versionExtractRegex": "v(\\d+\\.\\d+\\.\\d+),", + "versionExtractRegex": "v(\\d+\\.\\d+\\.\\d+)", "versionExtractRegexFlags": "" }, "defaultInst": { @@ -409,42 +840,6 @@ "portRef": "rustup_rustlang@0.1.0" } }, - "bciqjcmf46h2h6teenwbsda35igg4hea6ro5vh6nfieehk4jkuiqaj2a": { - "manifest": { - "ty": "denoWorker@v1", - "name": "rust_rustup", - "platforms": [ - "x86_64-linux", - "aarch64-linux", - "x86_64-darwin", - "aarch64-darwin", - "x86_64-windows", - "aarch64-windows", - "x86_64-freebsd", - "aarch64-freebsd", - "x86_64-netbsd", - "aarch64-netbsd", - "x86_64-aix", - "aarch64-aix", - "x86_64-solaris", - "aarch64-solaris", - "x86_64-illumos", - "aarch64-illumos", - "x86_64-android", - "aarch64-android" - ], - "version": "0.1.0", - "buildDeps": [ - { - "name": "rustup_rustlang" - } - ], - "moduleSpecifier": "file:///ports/rust.ts" - }, - "defaultInst": { - "portRef": "rust_rustup@0.1.0" - } - }, "bciqpgt5wsiw4y7qzovqbt2yrdgq5mvhhjpcg6cxzt4w4taudyen44ca": { "manifest": { "ty": "denoWorker@v1", @@ -462,10 +857,10 @@ "portRef": "cargo_binstall_ghrel@0.1.0" } }, - "bciqo7cq7igschrhers3wiibbqpaavdf33fdfdalr4cu7gxr7cblifby": { + "bciqboouqnp54fnumgxvl7uay2k6ho4vhlbibvgoyyt5yt3rkwqaohzi": { "manifest": { "ty": "denoWorker@v1", - "name": "pnpm_ghrel", + "name": "node_org", "platforms": [ "aarch64-linux", "x86_64-linux", @@ -475,10 +870,15 @@ "x86_64-windows" ], "version": "0.1.0", - "moduleSpecifier": "file:///ports/pnpm.ts" + "buildDeps": [ + { + "name": "tar_aa" + } + ], + "moduleSpecifier": "file:///ports/node.ts" }, "defaultInst": { - "portRef": "pnpm_ghrel@0.1.0" + "portRef": "node_org@0.1.0" } }, "bciqoxx4uhfhw77sux6kzqhy6bvxhxkk4cqigrxdrmggillzkfjgjnli": { @@ -510,71 +910,162 @@ "portRef": "asdf_plugin_git@0.1.0" } }, - "bciqboouqnp54fnumgxvl7uay2k6ho4vhlbibvgoyyt5yt3rkwqaohzi": { - "manifest": { + "bciqdg64uhkvlkqyc7nli33cja3aolbcdr75qepnrhj5ojlifsvxqzgq": { + "cpy_bs_ghrel": "bciqdfarczmlu3r5dkvcdoultfbnuvn6saao55h4fbb3jg72kv6mkr3y", + "rust_rustup": "bciqgze4knhjfbiypt5axkjslfsduq6tbwszbiuy5zsgpacrm5h6cg4a", + "tar_aa": "bciqb6ua63xodzwxngnbjq35hfikiwzb3dclbqkc7e6xgjdt5jin4pia", + "git_aa": "bciqfl5s36w335ducrb6f6gwb3vuwup7vzqwwg67pq42xtkngsnxqobi", + "curl_aa": "bciqcfe7qyxmokpn6pgtaj35r5qg74jkehuu6cvyrtcsnegvwlm64oqy", + "unzip_aa": "bciqgkpwxjmo5phw5se4ugyiz4xua3xrd54quzmk7wdwpq3vghglogjy", + "zstd_aa": "bciqpezvwy56igv7hqdpb3qreewqmyftjyej7zhcyhz6afcgfxgy3rjy", + "rustup_rustlang": "bciqk4ivbyqvpxwcaj5reufmveqldiizo6xmqiqq7njtaczgappydoka", + "cargo_binstall_ghrel": "bciqpgt5wsiw4y7qzovqbt2yrdgq5mvhhjpcg6cxzt4w4taudyen44ca", + "node_org": "bciqboouqnp54fnumgxvl7uay2k6ho4vhlbibvgoyyt5yt3rkwqaohzi", + "asdf_plugin_git": "bciqoxx4uhfhw77sux6kzqhy6bvxhxkk4cqigrxdrmggillzkfjgjnli" + }, + "bciqikjfnbntvagpghawbzlfp2es6lnqzhba3qx5de7tdrmvhuzhsjqa": { + "port": { "ty": "denoWorker@v1", - "name": "node_org", + "name": "protoc_ghrel", "platforms": [ "aarch64-linux", "x86_64-linux", "aarch64-darwin", + "x86_64-darwin" + ], + "version": "0.1.0", + "moduleSpecifier": "file:///ports/protoc.ts" + } + }, + "bciqfrfun7z7soj7yxzziyvmt2jnebqvneeoozk5vynmg5pa6wqynhvi": { + "port": { + "ty": "denoWorker@v1", + "name": "pipi_pypi", + "platforms": [ + "x86_64-linux", + "aarch64-linux", "x86_64-darwin", + "aarch64-darwin", + "x86_64-windows", "aarch64-windows", - "x86_64-windows" + "x86_64-freebsd", + "aarch64-freebsd", + "x86_64-netbsd", + "aarch64-netbsd", + "x86_64-aix", + "aarch64-aix", + "x86_64-solaris", + "aarch64-solaris", + "x86_64-illumos", + "aarch64-illumos", + "x86_64-android", + "aarch64-android" ], "version": "0.1.0", "buildDeps": [ { - "name": "tar_aa" + "name": "cpy_bs_ghrel" } ], - "moduleSpecifier": "file:///ports/node.ts" + "moduleSpecifier": "file:///ports/pipi.ts" }, - "defaultInst": { - "portRef": "node_org@0.1.0" - } + "packageName": "cmake" }, - "bciqctvtiscapp6cmlaxuaxnyac664hs3y3xsa5kqh4ctmhbsiehusly": { - "manifest": { + "bciqgkc6fegmxehj4whmusfuurxyp4ayeysn6qa2t6q64baac5is7uui": { + "version": "1.82.0", + "port": { "ty": "denoWorker@v1", - "name": "cpy_bs_ghrel", + "name": "rust_rustup", "platforms": [ "x86_64-linux", "aarch64-linux", "x86_64-darwin", "aarch64-darwin", "x86_64-windows", - "aarch64-windows" + "aarch64-windows", + "x86_64-freebsd", + "aarch64-freebsd", + "x86_64-netbsd", + "aarch64-netbsd", + "x86_64-aix", + "aarch64-aix", + "x86_64-solaris", + "aarch64-solaris", + "x86_64-illumos", + "aarch64-illumos", + "x86_64-android", + "aarch64-android" ], "version": "0.1.0", "buildDeps": [ { - "name": "tar_aa" + "name": "rustup_rustlang" + } + ], + "moduleSpecifier": "file:///ports/rust.ts" + }, + "profile": "default", + "components": [ + "rust-src" + ] + }, + "bciqlfx3mm5hi37g75snjknph6fkniixjhnvyyfxeua7f5z4h7nnqtna": { + "port": { + "ty": "denoWorker@v1", + "name": "cargobi_cratesio", + "platforms": [ + "x86_64-linux", + "aarch64-linux", + "x86_64-darwin", + "aarch64-darwin", + "x86_64-windows", + "aarch64-windows", + "x86_64-freebsd", + "aarch64-freebsd", + "x86_64-netbsd", + "aarch64-netbsd", + "x86_64-aix", + "aarch64-aix", + "x86_64-solaris", + "aarch64-solaris", + "x86_64-illumos", + "aarch64-illumos", + "x86_64-android", + "aarch64-android" + ], + "version": "0.1.0", + "buildDeps": [ + { + "name": "cargo_binstall_ghrel" }, { - "name": "zstd_aa" + "name": "rust_rustup" } ], - "moduleSpecifier": "file:///ports/cpy_bs.ts" + "moduleSpecifier": "file:///ports/cargobi.ts" }, - "defaultInst": { - "portRef": "cpy_bs_ghrel@0.1.0" - } + "crateName": "tokio-console" }, - "bciqjx7llw7t6pfczypzmhbwv7sxaicruj5pdbuac47m4c5qyildiowi": { - "tar_aa": "bciqb6ua63xodzwxngnbjq35hfikiwzb3dclbqkc7e6xgjdt5jin4pia", - "git_aa": "bciqfl5s36w335ducrb6f6gwb3vuwup7vzqwwg67pq42xtkngsnxqobi", - "curl_aa": "bciqcfe7qyxmokpn6pgtaj35r5qg74jkehuu6cvyrtcsnegvwlm64oqy", - "unzip_aa": "bciqgkpwxjmo5phw5se4ugyiz4xua3xrd54quzmk7wdwpq3vghglogjy", - "zstd_aa": "bciqmcvyepuficjj3mwshsbfecwdmzch5gwxqo557icnq4zujtdllh4a", - "rustup_rustlang": "bciqk4ivbyqvpxwcaj5reufmveqldiizo6xmqiqq7njtaczgappydoka", - "rust_rustup": "bciqjcmf46h2h6teenwbsda35igg4hea6ro5vh6nfieehk4jkuiqaj2a", - "cargo_binstall_ghrel": "bciqpgt5wsiw4y7qzovqbt2yrdgq5mvhhjpcg6cxzt4w4taudyen44ca", - "pnpm_ghrel": "bciqo7cq7igschrhers3wiibbqpaavdf33fdfdalr4cu7gxr7cblifby", - "asdf_plugin_git": "bciqoxx4uhfhw77sux6kzqhy6bvxhxkk4cqigrxdrmggillzkfjgjnli", - "node_org": "bciqboouqnp54fnumgxvl7uay2k6ho4vhlbibvgoyyt5yt3rkwqaohzi", - "cpy_bs_ghrel": "bciqctvtiscapp6cmlaxuaxnyac664hs3y3xsa5kqh4ctmhbsiehusly" - } + "bciqlmoqot4jk2lb2b34pldr5iiwsfm3biuipzesjkkwmc2n2o6nlw4q": { + "version": "v2.4.0", + "port": { + "ty": "denoWorker@v1", + "name": "mold_ghrel", + "platforms": [ + "aarch64-linux", + "x86_64-linux" + ], + "version": "0.1.0", + "buildDeps": [ + { + "name": "tar_aa" + } + ], + "moduleSpecifier": "file:///ports/mold.ts" + }, + "replaceLd": true + }, + "bciqeie3punk3gz4kcfdk2fxx5bsj5fh3j7bb7z36qmimayhwdsvp7cq": {} } } -} +} \ No newline at end of file diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index fdb034a8..7d50999d 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -1,71 +1,66 @@ +name: nightly jobs on: schedule: - cron: "0 2 * * *" workflow_dispatch: env: - DENO_VERSION: "1.44.2" - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + DENO_VERSION: "2.1.2" + GHJK_LOG: debug GHJK_LOG_PANIC_LEVEL: error DENO_DIR: .deno-dir - DOCKER_NO_RMI: 1 + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} jobs: test-e2e: + timeout-minutes: 60 runs-on: "${{ matrix.os }}" strategy: fail-fast: false matrix: include: - os: ubuntu-latest - e2eType: "local" + platform: linux/x86_64 + - os: custom-arm + platform: linux/aarch64 - os: macos-latest - e2eType: "local" + platform: darwin/x86_64 - os: macos-14 - e2eType: "local" + platform: darwin/aarch64 # - os: windows-latest - # e2eType: "local" - env: - GHJK_TEST_E2E_TYPE: ${{ matrix.e2eType }} steps: - uses: actions/checkout@v4 + - uses: dsherret/rust-toolchain-file@v1 - uses: denoland/setup-deno@v1 with: deno-version: ${{ env.DENO_VERSION }} - - if: "${{ matrix.os == 'ubuntu-latest' || matrix.os == 'custom-arm' }}" - run: | - # we need coreutils on max for the `timeout` command - sudo apt update - sudo apt install -y --no-install-recommends fish zsh - - if: "${{ matrix.os == 'macos-latest' || matrix.os == 'macos-14' }}" - # we need coreutils on max for the `timeout` command - run: brew install fish zsh coreutils - name: Cache deno dir - if: "${{ matrix.os == 'macos-latest' || matrix.os == 'macos-14' }}" uses: actions/cache@v4 with: path: ${{ env.DENO_DIR }} - key: deno-mac-${{ hashFiles('**/deno.lock') }} - - - if: "${{ matrix.e2eType == 'docker' }}" - uses: docker/setup-buildx-action@v3 - - if: "${{ matrix.e2eType == 'docker' }}" - uses: actions-hub/docker/cli@master - env: - SKIP_LOGIN: true - + key: deno-${{ hashFiles('**/deno.lock') }} + - if: "${{ matrix.os == 'ubuntu-latest' || matrix.os == 'custom-arm' }}" + # need coreutils on max for the `timeout` command + # need cmake to build the rust deps + run: | + sudo apt update + sudo apt install -y --no-install-recommends fish zsh cmake + - if: "${{ matrix.os == 'macos-latest' || matrix.os == 'macos-14' }}" + # need cmake to build the rust deps + # need coreutils on max for the `timeout` command + run: brew install fish zsh coreutils cmake - run: deno task test - test-action: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: metatypedev/setup-ghjk@318209a9d215f70716a4ac89dbeb9653a2deb8bc - with: - installer-url: ./install.ts - env: - GHJKFILE: ./examples/protoc/ghjk.ts - - run: | - cd examples/tasks - . $(ghjk print share-dir-path)/env.sh - ghjk x hey + # test-action: + # runs-on: ubuntu-latest + # steps: + # - uses: actions/checkout@v4 + # - uses: metatypedev/setup-ghjk@318209a9d215f70716a4ac89dbeb9653a2deb8bc + # with: + # installer-url: ./install.ts + # env: + # GHJKFILE: ./examples/protoc/ghjk.ts + # - run: | + # cd examples/tasks + # . $(ghjk print share-dir-path)/env.sh + # ghjk x hey diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..383e77f4 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,90 @@ +name: release jobs +run-name: release jobs for ${{ github.ref }} +on: + workflow_dispatch: + inputs: + ovewriteArtifacts: + description: Ovewrite artifacts on the release. Some will only be skipped. + required: true + type: boolean + default: true + checkBump: + description: check-bump adds a release entry to github so it's disabled by default. + required: true + type: boolean + default: false + push: + tags: + - v* + +jobs: + check-bump: + runs-on: ubuntu-latest + if: github.ref_type == 'tag' || ( github.event_name == 'workflow_dispatch' && inputs.checkBump ) + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: WyriHaximus/github-action-get-previous-tag@v1.4.0 + id: latest-tag + - uses: ncipollo/release-action@v1 + with: + tag: ${{ steps.latest-tag.outputs.tag }} + allowUpdates: ${{ github.event_name == 'workflow_dispatch' }} + generateReleaseNotes: true + discussionCategory: "Announcements" + prerelease: ${{ contains(steps.latest-tag.outputs.tag, 'rc') || contains(steps.latest-tag.outputs.tag, 'dev') }} + + pub-cli: + needs: + - check-bump + # using `always()` makes the job evaulte despite + # status of check-bump + # we combine that with our own conditions + if: | + always() + && ( + needs.check-bump.result == 'success' + || github.event_name == 'workflow_dispatch' + ) + runs-on: "${{ matrix.os }}" + strategy: + fail-fast: false + matrix: + include: + - os: macos-13 + target: x86_64-apple-darwin + - os: macos-14 + target: aarch64-apple-darwin + - os: ubuntu-latest + target: x86_64-unknown-linux-gnu + # FIXME: deno doesn't support musl today https://github.com/denoland/deno/issues/3711 + # - os: ubuntu-latest + # target: x86_64-unknown-linux-musl + - os: custom-arm + target: aarch64-unknown-linux-gnu + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + # some targets don't use cross so will require the deps in the host + - uses: WyriHaximus/github-action-get-previous-tag@v1.4.0 + id: latest-tag + - uses: dsherret/rust-toolchain-file@v1 + with: + targets: ${{ matrix.target }} + - uses: mozilla-actions/sccache-action@v0.0.6 + - run: | + rustup target add ${{ matrix.target }} + - shell: bash + run: | + cargo build --release --locked --package ghjk --target ${{ matrix.target }} + cd target/${{ matrix.target }}/release/ + tar czvf ../../../ghjk-${{ steps.latest-tag.outputs.tag }}-${{ matrix.target }}.tar.gz ghjk + cd ../../../ + - uses: svenstaro/upload-release-action@v2 + with: + tag: ${{ steps.latest-tag.outputs.tag }} + file: "ghjk-${{ steps.latest-tag.outputs.tag }}-${{ matrix.target }}.tar.gz" + asset_name: "ghjk-${{ steps.latest-tag.outputs.tag }}-${{ matrix.target }}.tar.gz" + overwrite: ${{ inputs.ovewriteArtifacts }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 521cced9..1517cffc 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,3 +1,5 @@ +name: test suite +run-name: test suite for ${{ github.event.pull_request.title || github.ref }} on: push: branches: @@ -8,14 +10,16 @@ on: - synchronize - ready_for_review +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + env: - DENO_VERSION: "1.44.2" + DENO_VERSION: "2.1.2" GHJK_LOG: debug GHJK_LOG_PANIC_LEVEL: error DENO_DIR: .deno-dir GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # removing the images after every test is unncessary - DOCKER_NO_RMI: 1 jobs: changes: @@ -26,9 +30,11 @@ jobs: - uses: actions/checkout@v4 test-pre-commit: + timeout-minutes: 60 runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - uses: dsherret/rust-toolchain-file@v1 - uses: denoland/setup-deno@v1 with: deno-version: ${{ env.DENO_VERSION }} @@ -36,12 +42,13 @@ jobs: # pre commit runs ghjk. We'll always see changes # to lock.json since GITHUB_TOKEN is different # in the CI - - run: deno run --unstable -A main.ts print config + - run: deno task self envs cook -t lock-sed - uses: pre-commit/action@v3.0.1 env: SKIP: ghjk-resolve test-e2e: + timeout-minutes: 60 runs-on: "${{ matrix.os }}" strategy: fail-fast: false @@ -49,22 +56,16 @@ jobs: include: - os: ubuntu-latest platform: linux/x86_64 - e2eType: "local" - os: custom-arm platform: linux/aarch64 - e2eType: "local" - os: macos-latest platform: darwin/x86_64 - e2eType: "local" - os: macos-14 platform: darwin/aarch64 - e2eType: "local" # - os: windows-latest - # e2eType: "local" - env: - GHJK_TEST_E2E_TYPE: ${{ matrix.e2eType }} steps: - uses: actions/checkout@v4 + - uses: dsherret/rust-toolchain-file@v1 - uses: denoland/setup-deno@v1 with: deno-version: ${{ env.DENO_VERSION }} @@ -73,31 +74,29 @@ jobs: with: path: ${{ env.DENO_DIR }} key: deno-${{ hashFiles('**/deno.lock') }} - - if: "${{ matrix.e2eType == 'docker' }}" - uses: docker/setup-buildx-action@v3 - if: "${{ matrix.os == 'ubuntu-latest' || matrix.os == 'custom-arm' }}" + # need coreutils on max for the `timeout` command + # need cmake to build the rust deps run: | - # we need coreutils on max for the `timeout` command sudo apt update - sudo apt install -y --no-install-recommends fish zsh + sudo apt install -y --no-install-recommends fish zsh cmake - if: "${{ matrix.os == 'macos-latest' || matrix.os == 'macos-14' }}" - # we need coreutils on max for the `timeout` command - run: brew install fish zsh coreutils - - env: - DOCKER_PLATFORM: ${{ matrix.platform }} - run: deno task test - + # need cmake to build the rust deps + # need coreutils on max for the `timeout` command + run: brew install fish zsh coreutils cmake + - run: deno task test - test-action: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: metatypedev/setup-ghjk@318209a9d215f70716a4ac89dbeb9653a2deb8bc - with: - installer-url: ./install.ts - env: - GHJKFILE: ./examples/protoc/ghjk.ts - - run: | - cd examples/tasks - . $(ghjk print share-dir-path)/env.sh - ghjk x hey + # test-action: + # runs-on: ubuntu-latest + # steps: + # - uses: actions/checkout@v4 + # - uses: dsherret/rust-toolchain-file@v1 + # - uses: metatypedev/setup-ghjk@318209a9d215f70716a4ac89dbeb9653a2deb8bc + # with: + # installer-url: ./install.ts + # env: + # GHJKFILE: ./examples/protoc/ghjk.ts + # - run: | + # cd examples/tasks + # . $(ghjk print share-dir-path)/env.sh + # ghjk x hey diff --git a/.gitignore b/.gitignore index 6e7b8fb3..269d8a0a 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,9 @@ npm deno.land jsr.io esm.sh + +src/play/*.rs + +# Added by cargo + +/target diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6ebf0045..a0766cc4 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,13 +15,13 @@ repos: - id: end-of-file-fixer # exclude all generated files exclude: | - (?x)^( - .ghjk/lock.json| - .ghjk/hash.json| - .ghjk/deno.lock| - deno.lock| - gh_action/.*.js - )$ + (?x)^( + .ghjk/lock.json| + .ghjk/hash.json| + .ghjk/deno.lock| + deno.lock| + gh_action/.*.js + )$ - repo: https://github.com/python-jsonschema/check-jsonschema rev: 0.28.2 hooks: @@ -38,12 +38,12 @@ repos: - id: ghjk-resolve name: Ghjk resolve language: system - entry: bash -c 'deno run --unstable -A main.ts p resolve' + entry: bash -c 'deno task self p resolve' pass_filenames: false - id: lock-sed name: Sed lock language: system - entry: bash -c 'deno run --unstable -A main.ts x lock-sed' + entry: bash -c 'deno task self x lock-sed' pass_filenames: false - id: deno-fmt name: Deno format @@ -66,3 +66,15 @@ repos: pass_filenames: false types: - ts + - repo: https://github.com/doublify/pre-commit-rust + rev: v1.0 + hooks: + - id: fmt + - id: clippy + args: + - "--locked" + - "--all-features" + - "--all-targets" + - "--" + - "--deny" + - "warnings" diff --git a/.vscode/settings.json b/.vscode/settings.json index 0fae416b..6317ba2c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,7 @@ { "deno.enablePaths": [ - "." + ".", + "ghjk.ts" ], "deno.suggest.completeFunctionCalls": true, "deno.inlayHints.variableTypes.enabled": true, @@ -18,7 +19,16 @@ "editor.defaultFormatter": "denoland.vscode-deno" }, "cSpell.words": [ - "ghjk" + "DENO", + "ghjk", + "ghjkfile", + "ghjkfiles", + "Hashfile", + "indexmap", + "kwargs", + "POSIX", + "runtimes", + "sophon" ], "spellright.language": [ "en-US-10-1." diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 00000000..6b1776b2 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,9366 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aead-gcm-stream" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4947a169074c7e038fa43051d1c4e073f4488b0e4b0a30658f1e1a1b06449ce8" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + +[[package]] +name = "aes" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + +[[package]] +name = "aes-kw" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69fa2b352dcefb5f7f3a5fb840e02665d311d878955380515e4fd50095dd3d8c" +dependencies = [ + "aes", +] + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "serde", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "arbitrary" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" +dependencies = [ + "derive_arbitrary", +] + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +dependencies = [ + "serde", +] + +[[package]] +name = "ash" +version = "0.37.3+1.3.251" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e9c3835d686b0a6084ab4234fcd1b07dbf6e4767dce60874b12356a25ecd4a" +dependencies = [ + "libloading 0.7.4", +] + +[[package]] +name = "asn1-rs" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom 7.1.3", + "num-traits", + "rusticata-macros", + "thiserror", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "synstructure 0.12.6", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ast_node" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ab31376d309dd3bfc9cfb3c11c93ce0e0741bbe0354b20e7f8c60b044730b79" +dependencies = [ + "proc-macro2", + "quote", + "swc_macros_common", + "syn 2.0.87", +] + +[[package]] +name = "async-compression" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd066d0b4ef8ecb03a55319dc13aa6910616d0f44008a045bb1835af830abff5" +dependencies = [ + "brotli", + "flate2", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "async-stream" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "async-trait" +version = "0.1.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "asynchronous-codec" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a860072022177f903e59730004fb5dc13db9275b79bb2aef7ba8ce831956c233" +dependencies = [ + "bytes", + "futures-sink", + "futures-util", + "memchr", + "pin-project-lite", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "auto_impl" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "axum" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" +dependencies = [ + "async-trait", + "axum-core", + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "http-body-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "sync_wrapper", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper", + "tower-layer", + "tower-service", +] + +[[package]] +name = "az" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" + +[[package]] +name = "backtrace" +version = "0.3.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base32" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "022dfe9eb35f19ebbcb51e0b40a5ab759f46ad60cadf7297e0bd085afb50e076" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64-simd" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "781dd20c3aff0bd194fe7d2a977dd92f21c173891f3a03b677359e5fa457e5d5" +dependencies = [ + "simd-abstraction", +] + +[[package]] +name = "base64-simd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195" +dependencies = [ + "outref 0.5.1", + "vsimd", +] + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "better_scoped_tls" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "794edcc9b3fb07bb4aecaa11f093fd45663b4feadb782d68303a2268bc2701de" +dependencies = [ + "scoped-tls", +] + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bindgen" +version = "0.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" +dependencies = [ + "bitflags 2.6.0", + "cexpr", + "clang-sys", + "itertools 0.13.0", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.87", +] + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +dependencies = [ + "serde", +] + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-padding" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" +dependencies = [ + "generic-array", +] + +[[package]] +name = "boxed_error" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17d4f95e880cfd28c4ca5a006cf7f6af52b4bcb7b5866f573b2faa126fb7affb" +dependencies = [ + "quote", + "syn 2.0.87", +] + +[[package]] +name = "brotli" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bstr" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +dependencies = [ + "allocator-api2", +] + +[[package]] +name = "bytemuck" +version = "1.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" + +[[package]] +name = "cache_control" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bf2a5fb3207c12b5d208ebc145f967fea5cac41a021c37417ccc31ba40f39ee" + +[[package]] +name = "caseless" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808dab3318747be122cb31d36de18d4d1c81277a76f8332a02b81a3d73463d7f" +dependencies = [ + "regex", + "unicode-normalization", +] + +[[package]] +name = "cbc" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" +dependencies = [ + "cipher", +] + +[[package]] +name = "cc" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" +dependencies = [ + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom 7.1.3", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "num-traits", + "serde", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading 0.8.4", +] + +[[package]] +name = "clap" +version = "4.5.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", + "terminal_size", +] + +[[package]] +name = "clap_complete" +version = "4.5.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d7db6eca8c205649e8d3ccd05aa5042b1800a784e56bc7c43524fde8abbfa9b" +dependencies = [ + "clap", +] + +[[package]] +name = "clap_complete_fig" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d494102c8ff3951810c72baf96910b980fb065ca5d3101243e6a8dc19747c86b" +dependencies = [ + "clap", + "clap_complete", +] + +[[package]] +name = "clap_derive" +version = "4.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "clap_lex" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" + +[[package]] +name = "clipboard-win" +version = "5.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79f4473f5144e20d9aceaf2972478f06ddf687831eafeeb434fbaf0acc4144ad" +dependencies = [ + "error-code", +] + +[[package]] +name = "cmake" +version = "0.1.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" +dependencies = [ + "cc", +] + +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "color-eyre" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55146f5e46f237f7423d74111267d4597b59b0dad0ffaf7303bce9945d843ad5" +dependencies = [ + "backtrace", + "color-spantrace", + "eyre", + "indenter", + "once_cell", + "owo-colors", + "tracing-error", +] + +[[package]] +name = "color-print" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ee543c60ff3888934877a5671f45494dd27ed4ba25c6670b9a7576b7ed7a8c0" +dependencies = [ + "color-print-proc-macro", +] + +[[package]] +name = "color-print-proc-macro" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ff1a80c5f3cb1ca7c06ffdd71b6a6dd6d8f896c42141fbd43f50ed28dcdb93" +dependencies = [ + "nom 7.1.3", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "color-spantrace" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2" +dependencies = [ + "once_cell", + "owo-colors", + "tracing-core", + "tracing-error", +] + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "colorchoice" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" + +[[package]] +name = "comrak" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8c32ff8b21372fab0e9ecc4e42536055702dc5faa418362bffd1544f9d12637" +dependencies = [ + "caseless", + "derive_builder", + "entities", + "memchr", + "once_cell", + "regex", + "slug", + "typed-arena", + "unicode_categories", +] + +[[package]] +name = "config" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68578f196d2a33ff61b27fae256c3164f65e36382648e30666dde05b8cc9dfdf" +dependencies = [ + "async-trait", + "json5", + "nom 7.1.3", + "pathdiff", + "serde", + "serde_json", +] + +[[package]] +name = "console" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "unicode-width", + "windows-sys 0.52.0", +] + +[[package]] +name = "console-api" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8030735ecb0d128428b64cd379809817e620a40e5001c54465b99ec5feec2857" +dependencies = [ + "futures-core", + "prost", + "prost-types", + "tonic", + "tracing-core", +] + +[[package]] +name = "console-subscriber" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6539aa9c6a4cd31f4b1c040f860a1eac9aa80e7df6b05d506a6e7179936d6a01" +dependencies = [ + "console-api", + "crossbeam-channel", + "crossbeam-utils", + "futures-task", + "hdrhistogram", + "humantime", + "hyper-util", + "prost", + "prost-types", + "serde", + "serde_json", + "thread_local", + "tokio", + "tokio-stream", + "tonic", + "tracing", + "tracing-core", + "tracing-subscriber", +] + +[[package]] +name = "console_static_text" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4be93df536dfbcbd39ff7c129635da089901116b88bfc29ec1acb9b56f8ff35" +dependencies = [ + "unicode-width", + "vte", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "const_fn" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "373e9fafaa20882876db20562275ff58d50e0caa2590077fe7ce7bef90211d0d" + +[[package]] +name = "const_format" +version = "0.2.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c655d81ff1114fb0dcdea9225ea9f0cc712a6f8d189378e82bdf62a473a64b" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eff1a44b93f47b1bac19a27932f5c591e43d1ba357ee4f61526c8a25603f0eb1" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "cooked-waker" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147be55d677052dabc6b22252d5dd0fd4c29c8c27aa4f2fbef0f94aa003b406f" + +[[package]] +name = "cordyceps" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec10f0a762d93c4498d2e97a333805cb6250d60bead623f71d8034f9a4152ba3" +dependencies = [ + "loom", + "tracing", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "core-graphics-types" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "libc", +] + +[[package]] +name = "core2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" +dependencies = [ + "memchr", +] + +[[package]] +name = "countme" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crc" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49fc9a695bca7f35f5f4c15cddc84415f66a74ea78eef08e90c5024f2b540e23" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccaeedb56da03b09f598226e25e80088cb4cd25f316e6e4df7d695f0feeb1403" + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "rand_core", + "typenum", +] + +[[package]] +name = "css_dataset" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25670139e591f1c2869eb8d0d977028f8d05e859132b4c874ecd02a00d3c9174" + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto 0.2.9", + "rustc_version 0.4.0", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "d3d12" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b28bfe653d79bd16c77f659305b195b82bb5ce0c0eb2a4846b82ddbd77586813" +dependencies = [ + "bitflags 2.6.0", + "libloading 0.8.4", + "winapi", +] + +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.87", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", + "serde", +] + +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + +[[package]] +name = "data-url" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41b319d1b62ffbd002e057f36bebd1f42b9f97927c9577461d855f3513c4289f" + +[[package]] +name = "debug-ignore" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe7ed1d93f4553003e20b629abe9085e1e81b1429520f897f8f8860bc6dfc21" + +[[package]] +name = "debugid" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" +dependencies = [ + "serde", + "uuid", +] + +[[package]] +name = "deno" +version = "2.1.2" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" +dependencies = [ + "anstream", + "async-trait", + "base64 0.21.7", + "bincode", + "bytes", + "cache_control", + "chrono", + "clap", + "clap_complete", + "clap_complete_fig", + "color-print", + "console_static_text", + "dashmap", + "data-encoding", + "deno_ast", + "deno_cache_dir", + "deno_config", + "deno_core", + "deno_doc", + "deno_graph", + "deno_lint", + "deno_lockfile", + "deno_npm", + "deno_package_json", + "deno_path_util", + "deno_resolver", + "deno_runtime", + "deno_semver", + "deno_task_shell", + "deno_telemetry", + "deno_terminal 0.2.0", + "deno_tower_lsp", + "dissimilar", + "dotenvy", + "dprint-plugin-json", + "dprint-plugin-jupyter", + "dprint-plugin-markdown", + "dprint-plugin-typescript", + "env_logger", + "fancy-regex", + "faster-hex", + "flate2", + "fs3", + "glibc_version", + "glob", + "http 1.1.0", + "http-body 1.0.0", + "http-body-util", + "hyper-util", + "import_map", + "indexmap 2.6.0", + "jsonc-parser", + "junction", + "lazy-regex", + "libc", + "libsui", + "libz-sys", + "log", + "lsp-types", + "malva", + "markup_fmt", + "memmem", + "monch", + "nix 0.27.1", + "node_resolver", + "notify", + "once_cell", + "open", + "p256", + "pathdiff", + "percent-encoding", + "phf", + "pretty_yaml", + "quick-junit", + "rand", + "regex", + "ring", + "runtimelib", + "rustyline", + "rustyline-derive", + "serde", + "serde_json", + "serde_repr", + "sha2", + "shell-escape", + "spki", + "sqlformat", + "strsim", + "tar", + "tempfile", + "text-size", + "text_lines", + "thiserror", + "tokio", + "tokio-util", + "tracing", + "twox-hash", + "typed-arena", + "uuid", + "walkdir", + "which 4.4.2", + "winapi", + "winres", + "zeromq", + "zip", + "zstd", +] + +[[package]] +name = "deno-tower-lsp-macros" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05d59a1cfd445fd86f63616127a434aabca000e03d963b01b03ce813520565b9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "deno_ast" +version = "0.43.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d00b724e06d2081a141ec1155756a0b465d413d8e2a7515221f61d482eb2ee" +dependencies = [ + "base64 0.21.7", + "deno_media_type", + "deno_terminal 0.1.1", + "dprint-swc-ext", + "once_cell", + "percent-encoding", + "serde", + "sourcemap 9.1.0", + "swc_atoms", + "swc_bundler", + "swc_common", + "swc_config", + "swc_config_macro", + "swc_ecma_ast", + "swc_ecma_codegen", + "swc_ecma_codegen_macros", + "swc_ecma_loader", + "swc_ecma_parser", + "swc_ecma_transforms_base", + "swc_ecma_transforms_classes", + "swc_ecma_transforms_macros", + "swc_ecma_transforms_optimization", + "swc_ecma_transforms_proposal", + "swc_ecma_transforms_react", + "swc_ecma_transforms_typescript", + "swc_ecma_utils", + "swc_ecma_visit", + "swc_eq_ignore_macros", + "swc_graph_analyzer", + "swc_macros_common", + "swc_visit", + "swc_visit_macros", + "text_lines", + "thiserror", + "unicode-width", + "url", +] + +[[package]] +name = "deno_broadcast_channel" +version = "0.174.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" +dependencies = [ + "async-trait", + "deno_core", + "thiserror", + "tokio", + "uuid", +] + +[[package]] +name = "deno_cache" +version = "0.112.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" +dependencies = [ + "async-trait", + "deno_core", + "rusqlite", + "serde", + "sha2", + "thiserror", + "tokio", +] + +[[package]] +name = "deno_cache_dir" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c1f52170cd7715f8006da54cde1444863a0d6fbd9c11d037a737db2dec8e22" +dependencies = [ + "base32", + "deno_media_type", + "deno_path_util", + "indexmap 2.6.0", + "log", + "once_cell", + "parking_lot", + "serde", + "serde_json", + "sha2", + "thiserror", + "url", +] + +[[package]] +name = "deno_canvas" +version = "0.49.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" +dependencies = [ + "deno_core", + "deno_webgpu", + "image", + "serde", + "thiserror", +] + +[[package]] +name = "deno_config" +version = "0.39.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38fb809500238be2b10eee42944a47b3ac38974e1edbb47f73afcfca7df143bf" +dependencies = [ + "anyhow", + "deno_package_json", + "deno_path_util", + "deno_semver", + "glob", + "ignore", + "import_map", + "indexmap 2.6.0", + "jsonc-parser", + "log", + "percent-encoding", + "phf", + "serde", + "serde_json", + "thiserror", + "url", +] + +[[package]] +name = "deno_console" +version = "0.180.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" +dependencies = [ + "deno_core", +] + +[[package]] +name = "deno_core" +version = "0.323.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a781bcfe1b5211b8497f45bf5b3dba73036b8d5d1533c1f05d26ccf0afb25a78" +dependencies = [ + "anyhow", + "az", + "bincode", + "bit-set", + "bit-vec", + "bytes", + "cooked-waker", + "deno_core_icudata", + "deno_ops", + "deno_unsync", + "futures", + "indexmap 2.6.0", + "libc", + "memoffset", + "parking_lot", + "percent-encoding", + "pin-project", + "serde", + "serde_json", + "serde_v8", + "smallvec", + "sourcemap 8.0.1", + "static_assertions", + "tokio", + "url", + "v8", + "wasm_dep_analyzer", +] + +[[package]] +name = "deno_core_icudata" +version = "0.74.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe4dccb6147bb3f3ba0c7a48e993bfeb999d2c2e47a81badee80e2b370c8d695" + +[[package]] +name = "deno_cron" +version = "0.60.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" +dependencies = [ + "anyhow", + "async-trait", + "chrono", + "deno_core", + "saffron", + "thiserror", + "tokio", +] + +[[package]] +name = "deno_crypto" +version = "0.194.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" +dependencies = [ + "aes", + "aes-gcm", + "aes-kw", + "base64 0.21.7", + "cbc", + "const-oid", + "ctr", + "curve25519-dalek", + "deno_core", + "deno_web", + "ed448-goldilocks", + "elliptic-curve", + "num-traits", + "once_cell", + "p256", + "p384", + "p521", + "rand", + "ring", + "rsa", + "sec1", + "serde", + "serde_bytes", + "sha1", + "sha2", + "signature", + "spki", + "thiserror", + "tokio", + "uuid", + "x25519-dalek", +] + +[[package]] +name = "deno_doc" +version = "0.161.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32d994915f85e873865fc341e592080a487b0a987d06177016b2d93fd62162f8" +dependencies = [ + "anyhow", + "cfg-if", + "comrak", + "deno_ast", + "deno_graph", + "deno_path_util", + "handlebars", + "html-escape", + "import_map", + "indexmap 2.6.0", + "itoa", + "js-sys", + "lazy_static", + "percent-encoding", + "regex", + "serde", + "serde-wasm-bindgen", + "serde_json", + "termcolor", + "url", + "wasm-bindgen", +] + +[[package]] +name = "deno_fetch" +version = "0.204.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" +dependencies = [ + "base64 0.21.7", + "bytes", + "data-url", + "deno_core", + "deno_permissions", + "deno_tls", + "dyn-clone", + "error_reporter", + "hickory-resolver", + "http 1.1.0", + "http-body-util", + "hyper 1.5.0", + "hyper-rustls", + "hyper-util", + "ipnet", + "percent-encoding", + "rustls-webpki", + "serde", + "serde_json", + "thiserror", + "tokio", + "tokio-rustls", + "tokio-socks", + "tokio-util", + "tower", + "tower-http", + "tower-service", +] + +[[package]] +name = "deno_ffi" +version = "0.167.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" +dependencies = [ + "deno_core", + "deno_permissions", + "dlopen2 0.6.1", + "dynasmrt", + "libffi", + "libffi-sys", + "log", + "num-bigint", + "serde", + "serde-value", + "serde_json", + "thiserror", + "tokio", + "winapi", +] + +[[package]] +name = "deno_fs" +version = "0.90.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" +dependencies = [ + "async-trait", + "base32", + "boxed_error", + "deno_core", + "deno_io", + "deno_path_util", + "deno_permissions", + "filetime", + "junction", + "libc", + "nix 0.27.1", + "rand", + "rayon", + "serde", + "thiserror", + "winapi", + "windows-sys 0.52.0", +] + +[[package]] +name = "deno_graph" +version = "0.86.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c3f4be49dad28e794ff4eeb2daaf7956c97f8557097ef6f9c3ff1292e0a5c28" +dependencies = [ + "anyhow", + "async-trait", + "data-url", + "deno_ast", + "deno_semver", + "deno_unsync", + "encoding_rs", + "futures", + "import_map", + "indexmap 2.6.0", + "log", + "monch", + "once_cell", + "parking_lot", + "regex", + "serde", + "serde_json", + "sha2", + "thiserror", + "twox-hash", + "url", + "wasm_dep_analyzer", +] + +[[package]] +name = "deno_http" +version = "0.178.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" +dependencies = [ + "async-compression", + "async-trait", + "base64 0.21.7", + "brotli", + "bytes", + "cache_control", + "deno_core", + "deno_net", + "deno_websocket", + "flate2", + "http 0.2.12", + "http 1.1.0", + "httparse", + "hyper 0.14.29", + "hyper 1.5.0", + "hyper-util", + "itertools 0.10.5", + "memmem", + "mime", + "once_cell", + "percent-encoding", + "phf", + "pin-project", + "ring", + "scopeguard", + "serde", + "smallvec", + "thiserror", + "tokio", + "tokio-util", +] + +[[package]] +name = "deno_io" +version = "0.90.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" +dependencies = [ + "async-trait", + "deno_core", + "filetime", + "fs3", + "libc", + "log", + "once_cell", + "os_pipe", + "parking_lot", + "pin-project", + "rand", + "tokio", + "uuid", + "winapi", + "windows-sys 0.52.0", +] + +[[package]] +name = "deno_kv" +version = "0.88.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" +dependencies = [ + "anyhow", + "async-trait", + "base64 0.21.7", + "boxed_error", + "bytes", + "chrono", + "deno_core", + "deno_fetch", + "deno_path_util", + "deno_permissions", + "deno_tls", + "denokv_proto", + "denokv_remote", + "denokv_sqlite", + "faster-hex", + "http 1.1.0", + "http-body-util", + "log", + "num-bigint", + "prost", + "prost-build", + "rand", + "rusqlite", + "serde", + "thiserror", + "url", +] + +[[package]] +name = "deno_lint" +version = "0.68.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb994e6d1b18223df0a756c7948143b35682941d615edffef60d5b38822f38ac" +dependencies = [ + "anyhow", + "deno_ast", + "derive_more", + "if_chain", + "log", + "once_cell", + "phf", + "regex", + "serde", + "serde_json", +] + +[[package]] +name = "deno_lockfile" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579117d5815aa9bae0212637d6f4d5f45f9649bb2c8988dca434077545535039" +dependencies = [ + "deno_semver", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "deno_media_type" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcf552fbdedbe81c89705349d7d2485c7051382b000dfddbdbf7fc25931cf83" +dependencies = [ + "data-url", + "serde", + "url", +] + +[[package]] +name = "deno_napi" +version = "0.111.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" +dependencies = [ + "deno_core", + "deno_permissions", + "libc", + "libloading 0.7.4", + "log", + "napi_sym", + "thiserror", + "windows-sys 0.52.0", +] + +[[package]] +name = "deno_native_certs" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86bc737e098a45aa5742d51ce694ac7236a1e69fb0d9df8c862e9b4c9583c5f9" +dependencies = [ + "dlopen2 0.7.0", + "dlopen2_derive", + "once_cell", + "rustls-native-certs", + "rustls-pemfile", +] + +[[package]] +name = "deno_net" +version = "0.172.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" +dependencies = [ + "deno_core", + "deno_permissions", + "deno_tls", + "hickory-proto", + "hickory-resolver", + "pin-project", + "rustls-tokio-stream", + "serde", + "socket2", + "thiserror", + "tokio", +] + +[[package]] +name = "deno_node" +version = "0.117.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" +dependencies = [ + "aead-gcm-stream", + "aes", + "async-trait", + "base64 0.21.7", + "blake2", + "boxed_error", + "brotli", + "bytes", + "cbc", + "const-oid", + "data-encoding", + "deno_core", + "deno_fetch", + "deno_fs", + "deno_io", + "deno_media_type", + "deno_net", + "deno_package_json", + "deno_path_util", + "deno_permissions", + "deno_whoami", + "der", + "digest", + "dsa", + "ecb", + "ecdsa", + "ed25519-dalek", + "elliptic-curve", + "errno 0.2.8", + "faster-hex", + "h2 0.4.5", + "hkdf", + "home", + "http 1.1.0", + "http-body-util", + "hyper 1.5.0", + "hyper-util", + "idna 1.0.3", + "indexmap 2.6.0", + "ipnetwork", + "k256", + "lazy-regex", + "libc", + "libz-sys", + "md-5", + "md4", + "memchr", + "node_resolver", + "num-bigint", + "num-bigint-dig", + "num-integer", + "num-traits", + "once_cell", + "p224", + "p256", + "p384", + "path-clean", + "pbkdf2", + "pin-project-lite", + "pkcs8", + "rand", + "regex", + "ring", + "ripemd", + "rsa", + "scrypt", + "sec1", + "serde", + "sha1", + "sha2", + "sha3", + "signature", + "simd-json", + "sm3", + "spki", + "stable_deref_trait", + "thiserror", + "tokio", + "tokio-eld", + "url", + "webpki-root-certs", + "winapi", + "windows-sys 0.52.0", + "x25519-dalek", + "x509-parser", + "yoke", +] + +[[package]] +name = "deno_npm" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6b4dc4a9f1cff63d5638e7d93042f24f46300d1cc77b86f3caaa699a7ddccf7" +dependencies = [ + "anyhow", + "async-trait", + "deno_lockfile", + "deno_semver", + "futures", + "log", + "monch", + "serde", + "serde_json", + "thiserror", + "url", +] + +[[package]] +name = "deno_ops" +version = "0.199.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a24a1f3e22029a57d3094b32070b8328eac793920b5a022027d360f085e6b245" +dependencies = [ + "proc-macro-rules", + "proc-macro2", + "quote", + "stringcase", + "strum", + "strum_macros", + "syn 2.0.87", + "thiserror", +] + +[[package]] +name = "deno_package_json" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cbc4c4d3eb0960b58e8f43f9fc2d3f620fcac9a03cd85203e08db5b04e83c1f" +dependencies = [ + "deno_semver", + "indexmap 2.6.0", + "serde", + "serde_json", + "thiserror", + "url", +] + +[[package]] +name = "deno_path_util" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff25f6e08e7a0214bbacdd6f7195c7f1ebcd850c87a624e4ff06326b68b42d99" +dependencies = [ + "percent-encoding", + "thiserror", + "url", +] + +[[package]] +name = "deno_permissions" +version = "0.40.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" +dependencies = [ + "deno_core", + "deno_path_util", + "deno_terminal 0.2.0", + "fqdn", + "libc", + "log", + "once_cell", + "percent-encoding", + "serde", + "thiserror", + "which 4.4.2", + "winapi", +] + +[[package]] +name = "deno_resolver" +version = "0.12.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" +dependencies = [ + "anyhow", + "base32", + "boxed_error", + "dashmap", + "deno_config", + "deno_media_type", + "deno_package_json", + "deno_path_util", + "deno_semver", + "node_resolver", + "thiserror", + "url", +] + +[[package]] +name = "deno_runtime" +version = "0.189.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" +dependencies = [ + "color-print", + "deno_ast", + "deno_broadcast_channel", + "deno_cache", + "deno_canvas", + "deno_console", + "deno_core", + "deno_cron", + "deno_crypto", + "deno_fetch", + "deno_ffi", + "deno_fs", + "deno_http", + "deno_io", + "deno_kv", + "deno_napi", + "deno_net", + "deno_node", + "deno_path_util", + "deno_permissions", + "deno_telemetry", + "deno_terminal 0.2.0", + "deno_tls", + "deno_url", + "deno_web", + "deno_webgpu", + "deno_webidl", + "deno_websocket", + "deno_webstorage", + "dlopen2 0.6.1", + "encoding_rs", + "fastwebsockets", + "flate2", + "http 1.1.0", + "http-body-util", + "hyper 0.14.29", + "hyper 1.5.0", + "hyper-util", + "libc", + "log", + "netif", + "nix 0.27.1", + "node_resolver", + "notify", + "ntapi", + "once_cell", + "percent-encoding", + "regex", + "rustyline", + "same-file", + "serde", + "signal-hook", + "signal-hook-registry", + "tempfile", + "thiserror", + "tokio", + "tokio-metrics", + "twox-hash", + "uuid", + "which 4.4.2", + "winapi", + "windows-sys 0.52.0", +] + +[[package]] +name = "deno_semver" +version = "0.5.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c957c6a57c38b7dde2315df0da0ec228911e56a74f185b108a488d0401841a67" +dependencies = [ + "monch", + "once_cell", + "serde", + "thiserror", + "url", +] + +[[package]] +name = "deno_task_shell" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f444918f7102c1a5a143e9d57809e499fb4d365070519bf2e8bdb16d586af2a" +dependencies = [ + "anyhow", + "futures", + "glob", + "monch", + "os_pipe", + "path-dedot", + "thiserror", + "tokio", + "tokio-util", +] + +[[package]] +name = "deno_telemetry" +version = "0.2.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" +dependencies = [ + "async-trait", + "deno_core", + "http-body-util", + "hyper 1.5.0", + "hyper-util", + "log", + "once_cell", + "opentelemetry", + "opentelemetry-http", + "opentelemetry-otlp", + "opentelemetry-semantic-conventions", + "opentelemetry_sdk", + "pin-project", + "serde", + "tokio", +] + +[[package]] +name = "deno_terminal" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e6337d4e7f375f8b986409a76fbeecfa4bd8a1343e63355729ae4befa058eaf" +dependencies = [ + "once_cell", + "termcolor", +] + +[[package]] +name = "deno_terminal" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daef12499e89ee99e51ad6000a91f600d3937fb028ad4918af76810c5bc9e0d5" +dependencies = [ + "once_cell", + "termcolor", +] + +[[package]] +name = "deno_tls" +version = "0.167.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" +dependencies = [ + "deno_core", + "deno_native_certs", + "rustls", + "rustls-pemfile", + "rustls-tokio-stream", + "rustls-webpki", + "serde", + "thiserror", + "tokio", + "webpki-roots", +] + +[[package]] +name = "deno_tower_lsp" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7afb4d257c084fd889e8cf1ba3ad58db0002428c819cc7717815f996f97777a" +dependencies = [ + "async-trait", + "auto_impl", + "bytes", + "dashmap", + "deno-tower-lsp-macros", + "futures", + "httparse", + "lsp-types", + "memchr", + "serde", + "serde_json", + "tokio", + "tokio-util", + "tower", + "tracing", +] + +[[package]] +name = "deno_unsync" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f36b4ef61a04ce201b925a5dffa90f88437d37fee4836c758470dd15ba7f05e" +dependencies = [ + "parking_lot", + "tokio", +] + +[[package]] +name = "deno_url" +version = "0.180.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" +dependencies = [ + "deno_core", + "thiserror", + "urlpattern", +] + +[[package]] +name = "deno_web" +version = "0.211.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" +dependencies = [ + "async-trait", + "base64-simd 0.8.0", + "bytes", + "deno_core", + "deno_permissions", + "encoding_rs", + "flate2", + "futures", + "serde", + "thiserror", + "tokio", + "uuid", +] + +[[package]] +name = "deno_webgpu" +version = "0.147.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" +dependencies = [ + "deno_core", + "raw-window-handle", + "serde", + "thiserror", + "tokio", + "wgpu-core", + "wgpu-types", +] + +[[package]] +name = "deno_webidl" +version = "0.180.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" +dependencies = [ + "deno_core", +] + +[[package]] +name = "deno_websocket" +version = "0.185.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" +dependencies = [ + "bytes", + "deno_core", + "deno_net", + "deno_permissions", + "deno_tls", + "fastwebsockets", + "h2 0.4.5", + "http 1.1.0", + "http-body-util", + "hyper 1.5.0", + "hyper-util", + "once_cell", + "rustls-tokio-stream", + "serde", + "thiserror", + "tokio", +] + +[[package]] +name = "deno_webstorage" +version = "0.175.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" +dependencies = [ + "deno_core", + "deno_web", + "rusqlite", + "thiserror", +] + +[[package]] +name = "deno_whoami" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e75e4caa92b98a27f09c671d1399aee0f5970aa491b9a598523aac000a2192e3" +dependencies = [ + "libc", + "whoami", +] + +[[package]] +name = "denokv_proto" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7ba1f99ed11a9c11e868a8521b1f71a7e1aba785d7f42ea9ecbdc01146c89ec" +dependencies = [ + "anyhow", + "async-trait", + "chrono", + "futures", + "num-bigint", + "prost", + "serde", + "uuid", +] + +[[package]] +name = "denokv_remote" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08ed833073189e8f6d03155fe3b05a024e75e29d8a28a4c2e9ec3b5c925e727b" +dependencies = [ + "anyhow", + "async-stream", + "async-trait", + "bytes", + "chrono", + "denokv_proto", + "futures", + "http 1.1.0", + "log", + "prost", + "rand", + "serde", + "serde_json", + "tokio", + "tokio-util", + "url", + "uuid", +] + +[[package]] +name = "denokv_sqlite" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b790f01d1302d53a0c3cbd27de88a06b3abd64ec8ab8673924e490541c7c713" +dependencies = [ + "anyhow", + "async-stream", + "async-trait", + "chrono", + "denokv_proto", + "futures", + "hex", + "log", + "num-bigint", + "rand", + "rusqlite", + "serde_json", + "thiserror", + "tokio", + "tokio-stream", + "uuid", + "v8_valueserializer", +] + +[[package]] +name = "denort" +version = "0.3.0-rc.1" +dependencies = [ + "anyhow", + "color-eyre", + "deno", + "educe", + "tokio", + "tracing", + "tracing-subscriber", + "tracing-unwrap", +] + +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "der_derive", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "der-parser" +version = "8.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom 7.1.3", + "num-bigint", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "der_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", + "serde", +] + +[[package]] +name = "derive_arbitrary" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "derive_builder" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "derive_builder_macro" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" +dependencies = [ + "derive_builder_core", + "syn 2.0.87", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version 0.4.0", + "syn 1.0.109", +] + +[[package]] +name = "deunicode" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339544cc9e2c4dc3fc7149fd630c5f22263a4fdf18a98afd0075784968b5cf00" + +[[package]] +name = "dialoguer" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "658bce805d770f407bc62102fca7c2c64ceef2fbcb2b8bd19d2765ce093980de" +dependencies = [ + "console", + "shell-words", + "tempfile", + "thiserror", + "zeroize", +] + +[[package]] +name = "diatomic-waker" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab03c107fafeb3ee9f5925686dbb7a73bc76e3932abb0d2b365cb64b169cf04c" + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "directories" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "dissimilar" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c97b9233581d84b8e1e689cdd3a47b6f69770084fc246e86a7f78b0d9c1d4a5" + +[[package]] +name = "dlopen2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bc2c7ed06fd72a8513ded8d0d2f6fd2655a85d6885c48cae8625d80faf28c03" +dependencies = [ + "dlopen2_derive", + "libc", + "once_cell", + "winapi", +] + +[[package]] +name = "dlopen2" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1297103d2bbaea85724fcee6294c2d50b1081f9ad47d0f6f6f61eda65315a6" +dependencies = [ + "dlopen2_derive", + "libc", + "once_cell", + "winapi", +] + +[[package]] +name = "dlopen2_derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "document-features" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef5282ad69563b5fc40319526ba27e0e7363d552a896f0297d54f767717f9b95" +dependencies = [ + "litrs", +] + +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "dprint-core" +version = "0.66.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3ab0dd2bedc109d25f0d21afb09b7d329f6c6fa83b095daf31d2d967e091548" +dependencies = [ + "anyhow", + "bumpalo", + "hashbrown 0.14.5", + "indexmap 2.6.0", + "rustc-hash", + "serde", + "unicode-width", +] + +[[package]] +name = "dprint-core-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1675ad2b358481f3cc46202040d64ac7a36c4ade414a696df32e0e45421a6e9f" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "dprint-plugin-json" +version = "0.19.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57f91e594559b450b7c5d6a0ba9f3f9fe951c1ea371168f7c95973da3fdbd85a" +dependencies = [ + "anyhow", + "dprint-core", + "dprint-core-macros", + "jsonc-parser", + "serde", + "text_lines", +] + +[[package]] +name = "dprint-plugin-jupyter" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0d20684e37b3824e2bc917cfcb14e2cdf88398eef507335d839cbd78172bfee" +dependencies = [ + "anyhow", + "dprint-core", + "jsonc-parser", + "serde", + "serde_json", +] + +[[package]] +name = "dprint-plugin-markdown" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "934a8e33f6f373b2fb66c288a468e3dae9a56a6c66bfecd5504fe566131afd3f" +dependencies = [ + "anyhow", + "dprint-core", + "dprint-core-macros", + "pulldown-cmark", + "regex", + "serde", + "unicode-width", +] + +[[package]] +name = "dprint-plugin-typescript" +version = "0.93.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff29fd136541e59d51946f0d2d353fefc886776f61a799ebfb5838b06cef13b" +dependencies = [ + "anyhow", + "deno_ast", + "dprint-core", + "dprint-core-macros", + "percent-encoding", + "rustc-hash", + "serde", +] + +[[package]] +name = "dprint-swc-ext" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ba28c12892aadb751c2ba7001d8460faee4748a04b4edc51c7121cc67ee03db" +dependencies = [ + "allocator-api2", + "bumpalo", + "num-bigint", + "rustc-hash", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_ecma_parser", + "text_lines", +] + +[[package]] +name = "dsa" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48bc224a9084ad760195584ce5abb3c2c34a225fa312a128ad245a6b412b7689" +dependencies = [ + "digest", + "num-bigint-dig", + "num-traits", + "pkcs8", + "rfc6979", + "sha2", + "signature", + "zeroize", +] + +[[package]] +name = "dyn-clone" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" + +[[package]] +name = "dynasm" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "add9a102807b524ec050363f09e06f1504214b0e1c7797f64261c891022dce8b" +dependencies = [ + "bitflags 1.3.2", + "byteorder", + "lazy_static", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "dynasmrt" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64fba5a42bd76a17cad4bfa00de168ee1cbfa06a5e8ce992ae880218c05641a9" +dependencies = [ + "byteorder", + "dynasm", + "memmap2", +] + +[[package]] +name = "ecb" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a8bfa975b1aec2145850fcaa1c6fe269a16578c44705a532ae3edc92b8881c7" +dependencies = [ + "cipher", +] + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +dependencies = [ + "curve25519-dalek", + "ed25519", + "rand_core", + "serde", + "sha2", + "signature", + "subtle", + "zeroize", +] + +[[package]] +name = "ed448-goldilocks" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06924531e9e90130842b012e447f85bdaf9161bc8a0f8092be8cb70b01ebe092" +dependencies = [ + "fiat-crypto 0.1.20", + "hex", + "subtle", + "zeroize", +] + +[[package]] +name = "editpe" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48cede2bb1b07dd598d269f973792c43e0cd92686d3b452bd6e01d7a8eb01211" +dependencies = [ + "debug-ignore", + "indexmap 2.6.0", + "log", + "thiserror", + "zerocopy", +] + +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "base64ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "hkdf", + "pem-rfc7468", + "pkcs8", + "rand_core", + "sec1", + "serde_json", + "serdect", + "subtle", + "zeroize", +] + +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" + +[[package]] +name = "entities" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5320ae4c3782150d900b79807611a59a99fc9a1d61d686faafc24b93fc8d7ca" + +[[package]] +name = "enum-as-inner" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "enum-ordinalize" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "env_logger" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi", +] + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "error-code" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0474425d51df81997e2f90a21591180b38eccf27292d755f3e30750225c175b" + +[[package]] +name = "error_reporter" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31ae425815400e5ed474178a7a22e275a9687086a12ca63ec793ff292d8fdae8" + +[[package]] +name = "eyre" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + +[[package]] +name = "fancy-regex" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0678ab2d46fa5195aaf59ad034c083d351377d4af57f3e073c074d0da3e3c766" +dependencies = [ + "bit-set", + "regex", +] + +[[package]] +name = "faster-hex" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2a2b11eda1d40935b26cf18f6833c526845ae8c41e58d09af6adeb6f0269183" +dependencies = [ + "serde", +] + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "fastrand" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" + +[[package]] +name = "fastwebsockets" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26da0c7b5cef45c521a6f9cdfffdfeb6c9f5804fbac332deb5ae254634c7a6be" +dependencies = [ + "base64 0.21.7", + "bytes", + "http-body-util", + "hyper 1.5.0", + "hyper-util", + "pin-project", + "rand", + "sha1", + "simdutf8", + "thiserror", + "tokio", + "utf-8", +] + +[[package]] +name = "fd-lock" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e5768da2206272c81ef0b5e951a41862938a6070da63bcea197899942d3b947" +dependencies = [ + "cfg-if", + "rustix", + "windows-sys 0.52.0", +] + +[[package]] +name = "fdeflate" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77" + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "filetime" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.4.1", + "windows-sys 0.52.0", +] + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + +[[package]] +name = "flate2" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +dependencies = [ + "crc32fast", + "libz-sys", + "miniz_oxide", +] + +[[package]] +name = "float-cmp" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b09cf3155332e944990140d967ff5eceb70df778b34f77d8075db46e4704e6d8" +dependencies = [ + "num-traits", +] + +[[package]] +name = "fluent-uri" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17c704e9dbe1ddd863da1e6ff3567795087b1eb201ce80d8fa81162e1516500d" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fqdn" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08b1eaa7dfddeab6036292995620bf0435712e619db6d7690605897e76975eb0" + +[[package]] +name = "from_variant" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc9cc75639b041067353b9bce2450d6847e547276c6fbe4487d7407980e07db" +dependencies = [ + "proc-macro2", + "swc_macros_common", + "syn 2.0.87", +] + +[[package]] +name = "fs3" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb17cf6ed704f72485332f6ab65257460c4f9f3083934cf402bf9f5b3b600a90" +dependencies = [ + "libc", + "rustc_version 0.2.3", + "winapi", +] + +[[package]] +name = "fsevent-sys" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" +dependencies = [ + "libc", +] + +[[package]] +name = "fslock" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04412b8935272e3a9bae6f48c7bfff74c2911f60525404edfdd28e49884c3bfb" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-buffered" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34acda8ae8b63fbe0b2195c998b180cff89a8212fb2622a78b572a9f1c6f7684" +dependencies = [ + "cordyceps", + "diatomic-waker", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-concurrency" +version = "7.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b724496da7c26fcce66458526ce68fc2ecf4aaaa994281cf322ded5755520c" +dependencies = [ + "fixedbitset 0.5.7", + "futures-buffered", + "futures-core", + "futures-lite", + "pin-project", + "slab", + "smallvec", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "fastrand 1.9.0", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generator" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" +dependencies = [ + "cc", + "libc", + "log", + "rustversion", + "windows", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + +[[package]] +name = "ghjk" +version = "0.3.0-rc.1" +dependencies = [ + "ahash", + "anyhow", + "async-trait", + "bitflags 2.6.0", + "clap", + "clap_complete", + "color-eyre", + "config", + "console", + "console-subscriber", + "dashmap", + "data-encoding", + "deno_core", + "denort", + "dialoguer", + "directories", + "educe", + "futures", + "indexmap 2.6.0", + "itertools 0.13.0", + "json-canon", + "multihash", + "nix 0.29.0", + "once_cell", + "parking_lot", + "pathdiff", + "rand", + "regex", + "serde", + "serde_json", + "sha2", + "shadow-rs", + "smallvec", + "smartstring", + "thiserror", + "time", + "tokio", + "tokio-stream", + "tracing", + "tracing-appender", + "tracing-error", + "tracing-futures", + "tracing-subscriber", + "tracing-unwrap", +] + +[[package]] +name = "gimli" +version = "0.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" + +[[package]] +name = "git2" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b903b73e45dc0c6c596f2d37eccece7c1c8bb6e4407b001096387c63d0d93724" +dependencies = [ + "bitflags 2.6.0", + "libc", + "libgit2-sys", + "log", + "url", +] + +[[package]] +name = "gl_generator" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" +dependencies = [ + "khronos_api", + "log", + "xml-rs", +] + +[[package]] +name = "glibc_version" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "803ff7635f1ab4e2c064b68a0c60da917d3d18dc8d086130f689d62ce4f1c33e" +dependencies = [ + "regex", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "globset" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", +] + +[[package]] +name = "glow" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd348e04c43b32574f2de31c8bb397d96c9fcfa1371bd4ca6d8bdc464ab121b1" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "glutin_wgl_sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8098adac955faa2d31079b65dc48841251f69efd3ac25477903fc424362ead" +dependencies = [ + "gl_generator", +] + +[[package]] +name = "gpu-alloc" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" +dependencies = [ + "bitflags 2.6.0", + "gpu-alloc-types", +] + +[[package]] +name = "gpu-alloc-types" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] +name = "gpu-descriptor" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c08c1f623a8d0b722b8b99f821eb0ba672a1618f0d3b16ddbee1cedd2dd8557" +dependencies = [ + "bitflags 2.6.0", + "gpu-descriptor-types", + "hashbrown 0.14.5", +] + +[[package]] +name = "gpu-descriptor-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "gzip-header" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95cc527b92e6029a62960ad99aa8a6660faa4555fe5f731aab13aa6a921795a2" +dependencies = [ + "crc32fast", +] + +[[package]] +name = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap 2.6.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "h2" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.1.0", + "indexmap 2.6.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "halfbrown" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8588661a8607108a5ca69cab034063441a0413a0b041c13618a7dd348021ef6f" +dependencies = [ + "hashbrown 0.14.5", + "serde", +] + +[[package]] +name = "handlebars" +version = "6.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd4ccde012831f9a071a637b0d4e31df31c0f6c525784b35ae76a9ac6bc1e315" +dependencies = [ + "heck 0.5.0", + "log", + "num-order", + "pest", + "pest_derive", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", +] + +[[package]] +name = "hashbrown" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" + +[[package]] +name = "hashlink" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" +dependencies = [ + "hashbrown 0.14.5", +] + +[[package]] +name = "hdrhistogram" +version = "7.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "765c9198f173dd59ce26ff9f95ef0aafd0a0fe01fb9d72841bc5066a4c06511d" +dependencies = [ + "base64 0.21.7", + "byteorder", + "crossbeam-channel", + "flate2", + "nom 7.1.3", + "num-traits", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hexf-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" + +[[package]] +name = "hickory-proto" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07698b8420e2f0d6447a436ba999ec85d8fbf2a398bbd737b82cac4a2e96e512" +dependencies = [ + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna 0.4.0", + "ipnet", + "once_cell", + "rand", + "serde", + "thiserror", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "hickory-resolver" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28757f23aa75c98f254cf0405e6d8c25b831b32921b050a66692427679b1f243" +dependencies = [ + "cfg-if", + "futures-util", + "hickory-proto", + "ipconfig", + "lru-cache", + "once_cell", + "parking_lot", + "rand", + "resolv-conf", + "serde", + "smallvec", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + +[[package]] +name = "hstr" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96274be293b8877e61974a607105d09c84caebe9620b47774aa8a6b942042dd4" +dependencies = [ + "hashbrown 0.14.5", + "new_debug_unreachable", + "once_cell", + "phf", + "rustc-hash", + "triomphe", +] + +[[package]] +name = "html-escape" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d1ad449764d627e22bfd7cd5e8868264fc9236e07c752972b4080cd351cb476" +dependencies = [ + "utf8-width", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +dependencies = [ + "bytes", + "http 1.1.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "hyper" +version = "0.14.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f361cde2f109281a220d4307746cdfd5ee3f410da58a70377762396775634b33" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.3.26", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2 0.4.5", + "http 1.1.0", + "http-body 1.0.0", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" +dependencies = [ + "futures-util", + "http 1.1.0", + "hyper 1.5.0", + "hyper-util", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-timeout" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3203a961e5c83b6f5498933e78b6b263e208c197b63e9c6c53cc82ffd3f63793" +dependencies = [ + "hyper 1.5.0", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.1.0", + "http-body 1.0.0", + "hyper 1.5.0", + "pin-project-lite", + "socket2", + "tokio", + "tower", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "if_chain" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb56e1aa765b4b4f3aadfab769793b7087bb03a4ea4920644a6d238e2df5b9ed" + +[[package]] +name = "ignore" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492" +dependencies = [ + "globset", + "lazy_static", + "log", + "memchr", + "regex", + "same-file", + "thread_local", + "walkdir", + "winapi-util", +] + +[[package]] +name = "image" +version = "0.24.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5690139d2f55868e080017335e4b94cb7414274c74f1669c84fb5feba2c9f69d" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "num-traits", + "png", +] + +[[package]] +name = "import_map" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "351a787decc56f38d65d16d32687265045d6d6a4531b4a0e1b649def3590354e" +dependencies = [ + "indexmap 2.6.0", + "log", + "percent-encoding", + "serde", + "serde_json", + "thiserror", + "url", +] + +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +dependencies = [ + "equivalent", + "hashbrown 0.15.1", + "serde", +] + +[[package]] +name = "inotify" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" +dependencies = [ + "bitflags 1.3.2", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "block-padding", + "generic-array", +] + +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "ipconfig" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" +dependencies = [ + "socket2", + "widestring", + "windows-sys 0.48.0", + "winreg", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + +[[package]] +name = "ipnetwork" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf466541e9d546596ee94f9f69590f89473455f88372423e0008fc1a7daf100e" +dependencies = [ + "serde", +] + +[[package]] +name = "is-docker" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3" +dependencies = [ + "once_cell", +] + +[[package]] +name = "is-macro" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a85abdc13717906baccb5a1e435556ce0df215f242892f721dff62bf25288f" +dependencies = [ + "Inflector", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "is-terminal" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "is-wsl" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5" +dependencies = [ + "is-docker", + "once_cell", +] + +[[package]] +name = "is_debug" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06d198e9919d9822d5f7083ba8530e04de87841eaf21ead9af8f2304efd57c89" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "json-canon" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "447ae153a2bd47d61acc0d131295408e32ef87ed9785825a6f4ecef85afc0edb" +dependencies = [ + "ryu-js 0.2.2", + "serde", + "serde_json", +] + +[[package]] +name = "json5" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1" +dependencies = [ + "pest", + "pest_derive", + "serde", +] + +[[package]] +name = "jsonc-parser" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b558af6b49fd918e970471374e7a798b2c9bbcda624a210ffa3901ee5614bc8e" +dependencies = [ + "serde_json", +] + +[[package]] +name = "junction" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be39922b087cecaba4e2d5592dedfc8bda5d4a5a1231f143337cca207950b61d" +dependencies = [ + "scopeguard", + "winapi", +] + +[[package]] +name = "jupyter-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd71aa17c4fa65e6d7536ab2728881a41f8feb2ee5841c2240516c3c3d65d8b3" +dependencies = [ + "anyhow", + "serde", + "serde_json", + "thiserror", + "uuid", +] + +[[package]] +name = "k256" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2", + "signature", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "khronos-egl" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" +dependencies = [ + "libc", + "libloading 0.8.4", + "pkg-config", +] + +[[package]] +name = "khronos_api" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" + +[[package]] +name = "kqueue" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c" +dependencies = [ + "kqueue-sys", + "libc", +] + +[[package]] +name = "kqueue-sys" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" +dependencies = [ + "bitflags 1.3.2", + "libc", +] + +[[package]] +name = "lazy-regex" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d12be4595afdf58bd19e4a9f4e24187da2a66700786ff660a418e9059937a4c" +dependencies = [ + "lazy-regex-proc_macros", + "once_cell", + "regex", +] + +[[package]] +name = "lazy-regex-proc_macros" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44bcd58e6c97a7fcbaffcdc95728b393b8d98933bfadad49ed4097845b57ef0b" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "syn 2.0.87", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "libffi" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce826c243048e3d5cec441799724de52e2d42f820468431fc3fceee2341871e2" +dependencies = [ + "libc", + "libffi-sys", +] + +[[package]] +name = "libffi-sys" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36115160c57e8529781b4183c2bb51fdc1f6d6d1ed345591d84be7703befb3c" +dependencies = [ + "cc", +] + +[[package]] +name = "libgit2-sys" +version = "0.17.0+1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10472326a8a6477c3c20a64547b0059e4b0d086869eee31e6d7da728a8eb7224" +dependencies = [ + "cc", + "libc", + "libz-sys", + "pkg-config", +] + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "libloading" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d" +dependencies = [ + "cfg-if", + "windows-targets 0.52.5", +] + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.6.0", + "libc", +] + +[[package]] +name = "libsqlite3-sys" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "libsui" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89795977654ad6250d6c0915411b622bac22f9efb4f852af94b2e00964cab832" +dependencies = [ + "editpe", + "libc", + "sha2", + "windows-sys 0.48.0", + "zerocopy", +] + +[[package]] +name = "libz-sys" +version = "1.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" +dependencies = [ + "cc", + "cmake", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "litemap" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" + +[[package]] +name = "litrs" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +dependencies = [ + "serde", +] + +[[package]] +name = "loom" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "lsp-types" +version = "0.97.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53353550a17c04ac46c585feb189c2db82154fc84b79c7a66c96c2c644f66071" +dependencies = [ + "bitflags 1.3.2", + "fluent-uri", + "serde", + "serde_json", + "serde_repr", +] + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "malva" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c67b97ed99f56b86fa3c010843441f1fcdb71884bab96b8551bb3d1e7c6d529" +dependencies = [ + "aho-corasick", + "itertools 0.13.0", + "memchr", + "raffia", + "tiny_pretty", +] + +[[package]] +name = "markup_fmt" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f303c36143671ac6c54112eb5aa95649b169dae783fdb6ead2c0e88b408c425c" +dependencies = [ + "aho-corasick", + "css_dataset", + "itertools 0.13.0", + "memchr", + "tiny_pretty", +] + +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + +[[package]] +name = "md4" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da5ac363534dce5fabf69949225e174fbf111a498bf0ff794c8ea1fba9f3dda" +dependencies = [ + "digest", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "memmap2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +dependencies = [ + "libc", +] + +[[package]] +name = "memmem" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a64a92489e2744ce060c349162be1c5f33c6969234104dbd99ddb5feb08b8c15" + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "metal" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5637e166ea14be6063a3f8ba5ccb9a4159df7d8f6d61c02fc3d480b1f90dcfcb" +dependencies = [ + "bitflags 2.6.0", + "block", + "core-graphics-types", + "foreign-types", + "log", + "objc", + "paste", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "monch" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b52c1b33ff98142aecea13138bd399b68aa7ab5d9546c300988c345004001eea" + +[[package]] +name = "multihash" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc41f430805af9d1cf4adae4ed2149c759b877b01d909a1f40256188d09345d2" +dependencies = [ + "core2", + "unsigned-varint", +] + +[[package]] +name = "multimap" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" + +[[package]] +name = "naga" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e536ae46fcab0876853bd4a632ede5df4b1c2527a58f6c5a4150fe86be858231" +dependencies = [ + "arrayvec", + "bit-set", + "bitflags 2.6.0", + "codespan-reporting", + "hexf-parse", + "indexmap 2.6.0", + "log", + "num-traits", + "rustc-hash", + "serde", + "spirv", + "termcolor", + "thiserror", + "unicode-xid", +] + +[[package]] +name = "napi_sym" +version = "0.110.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" +dependencies = [ + "quote", + "serde", + "serde_json", + "syn 2.0.87", +] + +[[package]] +name = "ndk-sys" +version = "0.5.0+25.2.9519653" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "netif" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29a01b9f018d6b7b277fef6c79fdbd9bf17bb2d1e298238055cafab49baa5ee" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "nibble_vec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" +dependencies = [ + "smallvec", +] + +[[package]] +name = "nix" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "libc", +] + +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "cfg_aliases 0.2.1", + "libc", +] + +[[package]] +name = "node_resolver" +version = "0.19.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" +dependencies = [ + "anyhow", + "async-trait", + "boxed_error", + "deno_media_type", + "deno_package_json", + "deno_path_util", + "futures", + "lazy-regex", + "once_cell", + "path-clean", + "regex", + "serde_json", + "thiserror", + "tokio", + "url", +] + +[[package]] +name = "nom" +version = "5.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08959a387a676302eebf4ddbcbc611da04285579f76f88ee0506c63b1a61dd4b" +dependencies = [ + "memchr", + "version_check", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "notify" +version = "6.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" +dependencies = [ + "bitflags 2.6.0", + "crossbeam-channel", + "filetime", + "fsevent-sys", + "inotify", + "kqueue", + "libc", + "log", + "mio", + "walkdir", + "windows-sys 0.48.0", +] + +[[package]] +name = "ntapi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" +dependencies = [ + "winapi", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", + "rand", + "serde", +] + +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand", + "serde", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-modular" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17bb261bf36fa7d83f4c294f834e91256769097b3cb505d44831e0a179ac647f" + +[[package]] +name = "num-order" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537b596b97c40fcf8056d153049eb22f481c17ebce72a513ec9286e4986d1bb6" +dependencies = [ + "num-modular", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + +[[package]] +name = "oid-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" +dependencies = [ + "asn1-rs", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "open" +version = "5.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5ca541f22b1c46d4bb9801014f234758ab4297e7870b904b6a8415b980a7388" +dependencies = [ + "is-wsl", + "libc", + "pathdiff", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "opentelemetry" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab70038c28ed37b97d8ed414b6429d343a8bbf44c9f79ec854f3a643029ba6d7" +dependencies = [ + "futures-core", + "futures-sink", + "js-sys", + "pin-project-lite", + "thiserror", + "tracing", +] + +[[package]] +name = "opentelemetry-http" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a8a7f5f6ba7c1b286c2fbca0454eaba116f63bbe69ed250b642d36fbb04d80" +dependencies = [ + "async-trait", + "bytes", + "http 1.1.0", + "opentelemetry", +] + +[[package]] +name = "opentelemetry-otlp" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91cf61a1868dacc576bf2b2a1c3e9ab150af7272909e80085c3173384fe11f76" +dependencies = [ + "async-trait", + "futures-core", + "http 1.1.0", + "opentelemetry", + "opentelemetry-http", + "opentelemetry-proto", + "opentelemetry_sdk", + "prost", + "serde_json", + "thiserror", + "tokio", + "tonic", + "tracing", +] + +[[package]] +name = "opentelemetry-proto" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6e05acbfada5ec79023c85368af14abd0b307c015e9064d249b2a950ef459a6" +dependencies = [ + "hex", + "opentelemetry", + "opentelemetry_sdk", + "prost", + "serde", + "tonic", +] + +[[package]] +name = "opentelemetry-semantic-conventions" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc1b6902ff63b32ef6c489e8048c5e253e2e4a803ea3ea7e783914536eb15c52" + +[[package]] +name = "opentelemetry_sdk" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "231e9d6ceef9b0b2546ddf52335785ce41252bc7474ee8ba05bfad277be13ab8" +dependencies = [ + "async-trait", + "futures-channel", + "futures-executor", + "futures-util", + "glob", + "opentelemetry", + "percent-encoding", + "rand", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "ordered-float" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +dependencies = [ + "num-traits", +] + +[[package]] +name = "os_pipe" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57119c3b893986491ec9aa85056780d3a0f3cf4da7cc09dd3650dbd6c6738fb9" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "outref" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f222829ae9293e33a9f5e9f440c6760a3d450a64affe1846486b140db81c1f4" + +[[package]] +name = "outref" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4030760ffd992bef45b0ae3f10ce1aba99e33464c90d14dd7c039884963ddc7a" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "owo-colors" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" + +[[package]] +name = "p224" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30c06436d66652bc2f01ade021592c80a2aad401570a18aa18b82e440d2b9aa1" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "p384" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "p521" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc9e2161f1f215afdfce23677034ae137bbd45016a880c2eb3ba8eb95f085b2" +dependencies = [ + "base16ct", + "ecdsa", + "elliptic-curve", + "primeorder", + "rand_core", + "sha2", +] + +[[package]] +name = "parking" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.5.2", + "smallvec", + "windows-targets 0.52.5", +] + +[[package]] +name = "password-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "path-clean" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecba01bf2678719532c5e3059e0b5f0811273d94b397088b82e3bd0a78c78fdd" + +[[package]] +name = "path-dedot" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07ba0ad7e047712414213ff67533e6dd477af0a4e1d14fb52343e53d30ea9397" +dependencies = [ + "once_cell", +] + +[[package]] +name = "pathdiff" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c5ce1153ab5b689d0c074c4e7fc613e942dfb7dd9eea5ab202d2ad91fe361" + +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest", + "hmac", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pest" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26293c9193fbca7b1a3bf9b79dc1e388e927e6cacaa78b4a3ab705a1d3d41459" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "pest_meta" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + +[[package]] +name = "petgraph" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +dependencies = [ + "fixedbitset 0.4.2", + "indexmap 2.6.0", +] + +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_macros", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs5" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e847e2c91a18bfa887dd028ec33f2fe6f25db77db3619024764914affe8b69a6" +dependencies = [ + "aes", + "cbc", + "der", + "pbkdf2", + "scrypt", + "sha2", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "pkcs5", + "rand_core", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "play" +version = "0.3.0-rc.1" +dependencies = [ + "clap", + "color-eyre", + "data-encoding", + "futures-concurrency", + "once_cell", + "sha2", + "tokio", + "tracing", + "tracing-subscriber", + "tracing-unwrap", +] + +[[package]] +name = "png" +version = "0.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "pretty_yaml" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dda9a64ee7296e82d1e0f4389383e6a7d8e6e2487d8391f7d028c131395fd376" +dependencies = [ + "rowan", + "tiny_pretty", + "yaml_parser", +] + +[[package]] +name = "prettyplease" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" +dependencies = [ + "proc-macro2", + "syn 2.0.87", +] + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-rules" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07c277e4e643ef00c1233393c673f655e3672cf7eb3ba08a00bdd0ea59139b5f" +dependencies = [ + "proc-macro-rules-macros", + "proc-macro2", + "syn 2.0.87", +] + +[[package]] +name = "proc-macro-rules-macros" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "207fffb0fe655d1d47f6af98cc2793405e85929bdbc420d685554ff07be27ac7" +dependencies = [ + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "profiling" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d84d1d7a6ac92673717f9f6d1518374ef257669c24ebc5ac25d5033828be58" + +[[package]] +name = "prost" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b0487d90e047de87f984913713b85c601c05609aad5b0df4b4573fbf69aa13f" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c1318b19085f08681016926435853bbf7858f9c082d0999b80550ff5d9abe15" +dependencies = [ + "bytes", + "heck 0.5.0", + "itertools 0.13.0", + "log", + "multimap", + "once_cell", + "petgraph", + "prettyplease", + "prost", + "prost-types", + "regex", + "syn 2.0.87", + "tempfile", +] + +[[package]] +name = "prost-derive" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9552f850d5f0964a4e4d0bf306459ac29323ddfbae05e35a7c0d35cb0803cc5" +dependencies = [ + "anyhow", + "itertools 0.13.0", + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "prost-types" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4759aa0d3a6232fb8dbdb97b61de2c20047c68aca932c7ed76da9d788508d670" +dependencies = [ + "prost", +] + +[[package]] +name = "psm" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +dependencies = [ + "cc", +] + +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "pulldown-cmark" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "679341d22c78c6c649893cbd6c3278dcbe9fc4faa62fea3a9296ae2b50c14625" +dependencies = [ + "bitflags 2.6.0", + "memchr", + "unicase", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quick-junit" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1a341ae463320e9f8f34adda49c8a85d81d4e8f34cce4397fb0350481552224" +dependencies = [ + "chrono", + "indexmap 2.6.0", + "quick-xml", + "strip-ansi-escapes", + "thiserror", + "uuid", +] + +[[package]] +name = "quick-xml" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "radix_fmt" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce082a9940a7ace2ad4a8b7d0b1eac6aa378895f18be598230c5f2284ac05426" + +[[package]] +name = "radix_trie" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +dependencies = [ + "endian-type", + "nibble_vec", +] + +[[package]] +name = "raffia" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c36f58fa7ad2f26bca656054c902becddeac5582df2bb31d4b4d2a148c62cfd5" +dependencies = [ + "raffia_macro", + "smallvec", +] + +[[package]] +name = "raffia_macro" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fdb50eb5bf734fa5a770680a61876a6ec77b99c1e0e52d1f18ad6ebfa85759f" +dependencies = [ + "heck 0.5.0", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "range-alloc" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8a99fddc9f0ba0a85884b8d14e3592853e787d581ca1816c91349b10e4eeab" + +[[package]] +name = "raw-window-handle" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] +name = "redox_users" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +dependencies = [ + "getrandom", + "libredox", + "thiserror", +] + +[[package]] +name = "ref-cast" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf0a6f84d5f1d581da8b41b47ec8600871962f2a528115b542b362d4b744931" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "relative-path" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" + +[[package]] +name = "resolv-conf" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" +dependencies = [ + "hostname", + "quick-error", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest", +] + +[[package]] +name = "ron" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" +dependencies = [ + "base64 0.21.7", + "bitflags 2.6.0", + "serde", + "serde_derive", +] + +[[package]] +name = "rowan" +version = "0.15.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a542b0253fa46e632d27a1dc5cf7b930de4df8659dc6e720b647fc72147ae3d" +dependencies = [ + "countme", + "hashbrown 0.14.5", + "rustc-hash", + "text-size", +] + +[[package]] +name = "rsa" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core", + "signature", + "spki", + "subtle", + "zeroize", +] + +[[package]] +name = "runtimelib" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe23ba9967355bbb1be2fb9a8e51bd239ffdf9c791fad5a9b765122ee2bde2e4" +dependencies = [ + "anyhow", + "base64 0.22.1", + "bytes", + "chrono", + "data-encoding", + "dirs", + "futures", + "glob", + "jupyter-serde", + "rand", + "ring", + "serde", + "serde_json", + "shellexpand", + "tokio", + "uuid", + "zeromq", +] + +[[package]] +name = "rusqlite" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e" +dependencies = [ + "bitflags 2.6.0", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver 0.9.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.23", +] + +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom 7.1.3", +] + +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags 2.6.0", + "errno 0.3.9", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.23.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f1a745511c54ba6d4465e8d5dfbd81b45791756de28d4981af70d6dca128f1e" +dependencies = [ + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" +dependencies = [ + "openssl-probe", + "rustls-pemfile", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" + +[[package]] +name = "rustls-tokio-stream" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22557157d7395bc30727745b365d923f1ecc230c4c80b176545f3f4f08c46e33" +dependencies = [ + "futures", + "rustls", + "socket2", + "tokio", +] + +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + +[[package]] +name = "rustyline" +version = "13.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02a2d683a4ac90aeef5b1013933f6d977bd37d51ff3f4dad829d4931a7e6be86" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "clipboard-win", + "fd-lock", + "home", + "libc", + "log", + "memchr", + "nix 0.27.1", + "radix_trie", + "unicode-segmentation", + "unicode-width", + "utf8parse", + "winapi", +] + +[[package]] +name = "rustyline-derive" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "107c3d5d7f370ac09efa62a78375f94d94b8a33c61d8c278b96683fb4dbf2d8d" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "ryu-js" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6518fc26bced4d53678a22d6e423e9d8716377def84545fe328236e3af070e7f" + +[[package]] +name = "ryu-js" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad97d4ce1560a5e27cec89519dc8300d1aa6035b099821261c651486a19e44d5" + +[[package]] +name = "saffron" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03fb9a628596fc7590eb7edbf7b0613287be78df107f5f97b118aad59fb2eea9" +dependencies = [ + "chrono", + "nom 5.1.3", +] + +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "scrypt" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f" +dependencies = [ + "password-hash", + "pbkdf2", + "salsa20", + "sha2", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "serdect", + "subtle", + "zeroize", +] + +[[package]] +name = "security-framework" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" +dependencies = [ + "bitflags 2.6.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "serde" +version = "1.0.215" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + +[[package]] +name = "serde-wasm-bindgen" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3b143e2833c57ab9ad3ea280d21fd34e285a42837aeb0ee301f4f41890fa00e" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + +[[package]] +name = "serde_bytes" +version = "0.11.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.215" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "serde_json" +version = "1.0.133" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +dependencies = [ + "indexmap 2.6.0", + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8725e1dfadb3a50f7e5ce0b1a540466f6ed3fe7a0fca2ac2b8b831d31316bd00" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "serde_v8" +version = "0.232.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c9feae92f7293fcc1a32a86be1a399859c0637e55dad8991d5258c43f7ff4d2" +dependencies = [ + "num-bigint", + "serde", + "smallvec", + "thiserror", + "v8", +] + +[[package]] +name = "serdect" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a84f14a19e9a014bb9f4512488d9829a68e04ecabffb0f9904cd1ace94598177" +dependencies = [ + "base16ct", + "serde", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha1_smol" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + +[[package]] +name = "shadow-rs" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58cfcd0643497a9f780502063aecbcc4a3212cbe4948fd25ee8fd179c2cf9a18" +dependencies = [ + "const_format", + "git2", + "is_debug", + "time", + "tzdb", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shell-escape" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f" + +[[package]] +name = "shell-words" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" + +[[package]] +name = "shellexpand" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da03fa3b94cc19e3ebfc88c4229c49d8f08cdbd1228870a45f0ffdf84988e14b" +dependencies = [ + "dirs", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + +[[package]] +name = "simd-abstraction" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cadb29c57caadc51ff8346233b5cec1d240b68ce55cf1afc764818791876987" +dependencies = [ + "outref 0.1.0", +] + +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[package]] +name = "simd-json" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1df0290e9bfe79ddd5ff8798ca887cd107b75353d2957efe9777296e17f26b5" +dependencies = [ + "getrandom", + "halfbrown", + "ref-cast", + "serde", + "serde_json", + "simdutf8", + "value-trait", +] + +[[package]] +name = "simdutf8" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "slotmap" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" +dependencies = [ + "version_check", +] + +[[package]] +name = "slug" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bd94acec9c8da640005f8e135a39fc0372e74535e6b368b7a04b875f784c8c4" +dependencies = [ + "deunicode", + "wasm-bindgen", +] + +[[package]] +name = "sm3" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebb9a3b702d0a7e33bc4d85a14456633d2b165c2ad839c5fd9a8417c1ab15860" +dependencies = [ + "digest", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +dependencies = [ + "serde", +] + +[[package]] +name = "smartstring" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" +dependencies = [ + "autocfg", + "serde", + "static_assertions", + "version_check", +] + +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "sourcemap" +version = "8.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "208d40b9e8cad9f93613778ea295ed8f3c2b1824217c6cfc7219d3f6f45b96d4" +dependencies = [ + "base64-simd 0.7.0", + "bitvec", + "data-encoding", + "debugid", + "if_chain", + "rustc-hash", + "rustc_version 0.2.3", + "serde", + "serde_json", + "unicode-id-start", + "url", +] + +[[package]] +name = "sourcemap" +version = "9.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d146f02f4bbbabbbe3da0f9cd3ea2ab779defc4ed1f070b5bd83ea48ed78811" +dependencies = [ + "base64-simd 0.7.0", + "bitvec", + "data-encoding", + "debugid", + "if_chain", + "rustc-hash", + "rustc_version 0.2.3", + "serde", + "serde_json", + "unicode-id-start", + "url", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "spirv" +version = "0.3.0+sdk-1.3.268.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "sqlformat" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c38684453189293372e6fffa3bed1015d20488ce4cc09a23de050fd7411e46" +dependencies = [ + "nom 7.1.3", + "once_cell", + "regex", + "unicode_categories", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "stacker" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c886bd4480155fd3ef527d45e9ac8dd7118a898a46530b7b94c3e21866259fce" +dependencies = [ + "cc", + "cfg-if", + "libc", + "psm", + "winapi", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "string_enum" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05e383308aebc257e7d7920224fa055c632478d92744eca77f99be8fa1545b90" +dependencies = [ + "proc-macro2", + "quote", + "swc_macros_common", + "syn 2.0.87", +] + +[[package]] +name = "stringcase" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04028eeb851ed08af6aba5caa29f2d59a13ed168cee4d6bd753aeefcf1d636b0" + +[[package]] +name = "strip-ansi-escapes" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ff8ef943b384c414f54aefa961dd2bd853add74ec75e7ac74cf91dba62bcfa" +dependencies = [ + "vte", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.87", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "swc_allocator" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76aa0eb65c0f39f9b6d82a7e5192c30f7ac9a78f084a21f270de1d8c600ca388" +dependencies = [ + "bumpalo", + "hashbrown 0.14.5", + "ptr_meta", + "rustc-hash", + "triomphe", +] + +[[package]] +name = "swc_atoms" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb6567e4e67485b3e7662b486f1565bdae54bd5b9d6b16b2ba1a9babb1e42125" +dependencies = [ + "hstr", + "once_cell", + "rustc-hash", + "serde", +] + +[[package]] +name = "swc_bundler" +version = "0.237.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c77c112c218a09635d99a45802a81b4f341d6c28c81076aa2c29ba3bcd9151a9" +dependencies = [ + "anyhow", + "crc", + "indexmap 2.6.0", + "is-macro", + "once_cell", + "parking_lot", + "petgraph", + "radix_fmt", + "relative-path", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_ecma_codegen", + "swc_ecma_loader", + "swc_ecma_parser", + "swc_ecma_transforms_base", + "swc_ecma_transforms_optimization", + "swc_ecma_utils", + "swc_ecma_visit", + "swc_fast_graph", + "swc_graph_analyzer", + "tracing", +] + +[[package]] +name = "swc_cached" +version = "0.3.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83406221c501860fce9c27444f44125eafe9e598b8b81be7563d7036784cd05c" +dependencies = [ + "ahash", + "anyhow", + "dashmap", + "once_cell", + "regex", + "serde", +] + +[[package]] +name = "swc_common" +version = "0.37.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12d0a8eaaf1606c9207077d75828008cb2dfb51b095a766bd2b72ef893576e31" +dependencies = [ + "ast_node", + "better_scoped_tls", + "cfg-if", + "either", + "from_variant", + "new_debug_unreachable", + "num-bigint", + "once_cell", + "rustc-hash", + "serde", + "siphasher", + "sourcemap 9.1.0", + "swc_allocator", + "swc_atoms", + "swc_eq_ignore_macros", + "swc_visit", + "tracing", + "unicode-width", + "url", +] + +[[package]] +name = "swc_config" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4740e53eaf68b101203c1df0937d5161a29f3c13bceed0836ddfe245b72dd000" +dependencies = [ + "anyhow", + "indexmap 2.6.0", + "serde", + "serde_json", + "swc_cached", + "swc_config_macro", +] + +[[package]] +name = "swc_config_macro" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c5f56139042c1a95b54f5ca48baa0e0172d369bcc9d3d473dad1de36bae8399" +dependencies = [ + "proc-macro2", + "quote", + "swc_macros_common", + "syn 2.0.87", +] + +[[package]] +name = "swc_ecma_ast" +version = "0.118.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6f866d12e4d519052b92a0a86d1ac7ff17570da1272ca0c89b3d6f802cd79df" +dependencies = [ + "bitflags 2.6.0", + "is-macro", + "num-bigint", + "phf", + "scoped-tls", + "serde", + "string_enum", + "swc_atoms", + "swc_common", + "unicode-id-start", +] + +[[package]] +name = "swc_ecma_codegen" +version = "0.155.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7641608ef117cfbef9581a99d02059b522fcca75e5244fa0cbbd8606689c6f" +dependencies = [ + "memchr", + "num-bigint", + "once_cell", + "serde", + "sourcemap 9.1.0", + "swc_allocator", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_ecma_codegen_macros", + "tracing", +] + +[[package]] +name = "swc_ecma_codegen_macros" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859fabde36db38634f3fad548dd5e3410c1aebba1b67a3c63e67018fa57a0bca" +dependencies = [ + "proc-macro2", + "quote", + "swc_macros_common", + "syn 2.0.87", +] + +[[package]] +name = "swc_ecma_loader" +version = "0.49.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55fa3d55045b97894bfb04d38aff6d6302ac8a6a38e3bb3dfb0d20475c4974a9" +dependencies = [ + "anyhow", + "pathdiff", + "serde", + "swc_atoms", + "swc_common", + "tracing", +] + +[[package]] +name = "swc_ecma_parser" +version = "0.149.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683dada14722714588b56481399c699378b35b2ba4deb5c4db2fb627a97fb54b" +dependencies = [ + "either", + "new_debug_unreachable", + "num-bigint", + "num-traits", + "phf", + "serde", + "smallvec", + "smartstring", + "stacker", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "tracing", + "typed-arena", +] + +[[package]] +name = "swc_ecma_transforms_base" +version = "0.145.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65f21494e75d0bd8ef42010b47cabab9caaed8f2207570e809f6f4eb51a710d1" +dependencies = [ + "better_scoped_tls", + "bitflags 2.6.0", + "indexmap 2.6.0", + "once_cell", + "phf", + "rustc-hash", + "serde", + "smallvec", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_ecma_parser", + "swc_ecma_utils", + "swc_ecma_visit", + "tracing", +] + +[[package]] +name = "swc_ecma_transforms_classes" +version = "0.134.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3d884594385bea9405a2e1721151470d9a14d3ceec5dd773c0ca6894791601" +dependencies = [ + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_ecma_transforms_base", + "swc_ecma_utils", + "swc_ecma_visit", +] + +[[package]] +name = "swc_ecma_transforms_macros" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "500a1dadad1e0e41e417d633b3d6d5de677c9e0d3159b94ba3348436cdb15aab" +dependencies = [ + "proc-macro2", + "quote", + "swc_macros_common", + "syn 2.0.87", +] + +[[package]] +name = "swc_ecma_transforms_optimization" +version = "0.208.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98d8447ea20ef76958a8240feef95743702485a84331e6df5bdbe7e383c87838" +dependencies = [ + "dashmap", + "indexmap 2.6.0", + "once_cell", + "petgraph", + "rustc-hash", + "serde_json", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_ecma_parser", + "swc_ecma_transforms_base", + "swc_ecma_transforms_macros", + "swc_ecma_utils", + "swc_ecma_visit", + "swc_fast_graph", + "tracing", +] + +[[package]] +name = "swc_ecma_transforms_proposal" +version = "0.179.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79938ff510fc647febd8c6c3ef4143d099fdad87a223680e632623d056dae2dd" +dependencies = [ + "either", + "rustc-hash", + "serde", + "smallvec", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_ecma_transforms_base", + "swc_ecma_transforms_classes", + "swc_ecma_transforms_macros", + "swc_ecma_utils", + "swc_ecma_visit", +] + +[[package]] +name = "swc_ecma_transforms_react" +version = "0.191.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76c76d8b9792ce51401d38da0fa62158d61f6d80d16d68fe5b03ce4bf5fba383" +dependencies = [ + "base64 0.21.7", + "dashmap", + "indexmap 2.6.0", + "once_cell", + "serde", + "sha1", + "string_enum", + "swc_allocator", + "swc_atoms", + "swc_common", + "swc_config", + "swc_ecma_ast", + "swc_ecma_parser", + "swc_ecma_transforms_base", + "swc_ecma_transforms_macros", + "swc_ecma_utils", + "swc_ecma_visit", +] + +[[package]] +name = "swc_ecma_transforms_typescript" +version = "0.198.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15455da4768f97186c40523e83600495210c11825d3a44db43383fd81eace88d" +dependencies = [ + "ryu-js 1.0.1", + "serde", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_ecma_transforms_base", + "swc_ecma_transforms_react", + "swc_ecma_utils", + "swc_ecma_visit", +] + +[[package]] +name = "swc_ecma_utils" +version = "0.134.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "029eec7dd485923a75b5a45befd04510288870250270292fc2c1b3a9e7547408" +dependencies = [ + "indexmap 2.6.0", + "num_cpus", + "once_cell", + "rustc-hash", + "ryu-js 1.0.1", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_ecma_visit", + "tracing", + "unicode-id", +] + +[[package]] +name = "swc_ecma_visit" +version = "0.104.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b1c6802e68e51f336e8bc9644e9ff9da75d7da9c1a6247d532f2e908aa33e81" +dependencies = [ + "new_debug_unreachable", + "num-bigint", + "swc_atoms", + "swc_common", + "swc_ecma_ast", + "swc_visit", + "tracing", +] + +[[package]] +name = "swc_eq_ignore_macros" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63db0adcff29d220c3d151c5b25c0eabe7e32dd936212b84cdaa1392e3130497" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "swc_fast_graph" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357e2c97bb51431d65080f25b436bc4e2fc1a7f64a643bc21a8353e478dc799f" +dependencies = [ + "indexmap 2.6.0", + "petgraph", + "rustc-hash", + "swc_common", +] + +[[package]] +name = "swc_graph_analyzer" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84e1d24a0d6e4066b42cfc00ab9b3109e314465aa199dd3e16849ed9566dce7" +dependencies = [ + "auto_impl", + "petgraph", + "swc_common", + "swc_fast_graph", + "tracing", +] + +[[package]] +name = "swc_macros_common" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f486687bfb7b5c560868f69ed2d458b880cebc9babebcb67e49f31b55c5bf847" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "swc_visit" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ceb044142ba2719ef9eb3b6b454fce61ab849eb696c34d190f04651955c613d" +dependencies = [ + "either", + "new_debug_unreachable", +] + +[[package]] +name = "swc_visit_macros" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92807d840959f39c60ce8a774a3f83e8193c658068e6d270dbe0a05e40e90b41" +dependencies = [ + "Inflector", + "proc-macro2", + "quote", + "swc_macros_common", + "syn 2.0.87", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" + +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "unicode-xid", +] + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tar" +version = "0.4.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "tempfile" +version = "3.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +dependencies = [ + "cfg-if", + "fastrand 2.1.0", + "rustix", + "windows-sys 0.52.0", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "terminal_size" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" +dependencies = [ + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "text-size" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "288cb548dbe72b652243ea797201f3d481a0609a967980fcc5b2315ea811560a" + +[[package]] +name = "text_lines" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fd5828de7deaa782e1dd713006ae96b3bee32d3279b79eb67ecf8072c059bcf" +dependencies = [ + "serde", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "itoa", + "libc", + "num-conv", + "num_threads", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tiny_pretty" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b3f46f0549180b9c6f7f76270903f1a06867c43a03998b99dce81aa1760c3b2" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c55115c6fbe2d2bef26eb09ad74bde02d8255476fc0c7b515ef09fbb35742d82" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "tracing", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-eld" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9166030f05d6bc5642bdb8f8c2be31eb3c02cd465d662bcdc2df82d4aa41a584" +dependencies = [ + "hdrhistogram", + "tokio", +] + +[[package]] +name = "tokio-macros" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "tokio-metrics" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eace09241d62c98b7eeb1107d4c5c64ca3bd7da92e8c218c153ab3a78f9be112" +dependencies = [ + "futures-util", + "pin-project-lite", + "tokio", + "tokio-stream", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +dependencies = [ + "rustls", + "rustls-pki-types", + "tokio", +] + +[[package]] +name = "tokio-socks" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51165dfa029d2a65969413a6cc96f354b86b464498702f174a4efa13608fd8c0" +dependencies = [ + "either", + "futures-util", + "thiserror", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +dependencies = [ + "bytes", + "futures-core", + "futures-io", + "futures-sink", + "futures-util", + "hashbrown 0.14.5", + "pin-project-lite", + "slab", + "tokio", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "tonic" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" +dependencies = [ + "async-stream", + "async-trait", + "axum", + "base64 0.22.1", + "bytes", + "h2 0.4.5", + "http 1.1.0", + "http-body 1.0.0", + "http-body-util", + "hyper 1.5.0", + "hyper-timeout", + "hyper-util", + "percent-encoding", + "pin-project", + "prost", + "socket2", + "tokio", + "tokio-stream", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "indexmap 1.9.3", + "pin-project", + "pin-project-lite", + "rand", + "slab", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8437150ab6bbc8c5f0f519e3d5ed4aa883a83dd4cdd3d1b21f9482936046cb97" +dependencies = [ + "async-compression", + "bitflags 2.6.0", + "bytes", + "futures-core", + "http 1.1.0", + "http-body 1.0.0", + "http-body-util", + "pin-project-lite", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-appender" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" +dependencies = [ + "crossbeam-channel", + "thiserror", + "time", + "tracing-subscriber", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-error" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" +dependencies = [ + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "parking_lot", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "tracing-unwrap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4e33415be97f5ae70322d6fefc696bbc08887d8835400d6c77f059469b30354" +dependencies = [ + "tracing", +] + +[[package]] +name = "triomphe" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6631e42e10b40c0690bf92f404ebcfe6e1fdb480391d15f17cc8e96eeed5369" +dependencies = [ + "serde", + "stable_deref_trait", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "twox-hash" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +dependencies = [ + "cfg-if", + "rand", + "static_assertions", +] + +[[package]] +name = "typed-arena" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "tz-rs" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33851b15c848fad2cf4b105c6bb66eb9512b6f6c44a4b13f57c53c73c707e2b4" +dependencies = [ + "const_fn", +] + +[[package]] +name = "tzdb" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b580f6b365fa89f5767cdb619a55d534d04a4e14c2d7e5b9a31e94598687fb1" +dependencies = [ + "iana-time-zone", + "tz-rs", + "tzdb_data", +] + +[[package]] +name = "tzdb_data" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "654c1ec546942ce0594e8d220e6b8e3899e0a0a8fe70ddd54d32a376dfefe3f8" +dependencies = [ + "tz-rs", +] + +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + +[[package]] +name = "unic-char-property" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" +dependencies = [ + "unic-char-range", +] + +[[package]] +name = "unic-char-range" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" + +[[package]] +name = "unic-common" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" + +[[package]] +name = "unic-ucd-ident" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e230a37c0381caa9219d67cf063aa3a375ffed5bf541a452db16e744bdab6987" +dependencies = [ + "unic-char-property", + "unic-char-range", + "unic-ucd-version", +] + +[[package]] +name = "unic-ucd-version" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" +dependencies = [ + "unic-common", +] + +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + +[[package]] +name = "unicode-id" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1b6def86329695390197b82c1e244a54a131ceb66c996f2088a3876e2ae083f" + +[[package]] +name = "unicode-id-start" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f322b60f6b9736017344fa0635d64be2f458fbc04eef65f6be22976dd1ffd5b" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" + +[[package]] +name = "unicode-width" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "unicode_categories" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" + +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + +[[package]] +name = "unsigned-varint" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb066959b24b5196ae73cb057f45598450d2c5f71460e98c49b738086eff9c06" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna 1.0.3", + "percent-encoding", + "serde", +] + +[[package]] +name = "urlpattern" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d" +dependencies = [ + "regex", + "serde", + "unic-ucd-ident", + "url", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8-width" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "uuid" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de17fd2f7da591098415cff336e12965a28061ddace43b59cb3c430179c9439" +dependencies = [ + "getrandom", + "serde", + "sha1_smol", +] + +[[package]] +name = "v8" +version = "130.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c23b5c2caff00209b03a716609b275acae94b02dd3b63c4648e7232a84a8402f" +dependencies = [ + "bindgen", + "bitflags 2.6.0", + "fslock", + "gzip-header", + "home", + "miniz_oxide", + "once_cell", + "paste", + "which 6.0.1", +] + +[[package]] +name = "v8_valueserializer" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97599c400fc79925922b58303e98fcb8fa88f573379a08ddb652e72cbd2e70f6" +dependencies = [ + "bitflags 2.6.0", + "encoding_rs", + "indexmap 2.6.0", + "num-bigint", + "serde", + "thiserror", + "wtf8", +] + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "value-trait" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9170e001f458781e92711d2ad666110f153e4e50bfd5cbd02db6547625714187" +dependencies = [ + "float-cmp", + "halfbrown", + "itoa", + "ryu", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "vsimd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" + +[[package]] +name = "vte" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5022b5fbf9407086c180e9557be968742d839e68346af7792b8592489732197" +dependencies = [ + "arrayvec", + "utf8parse", + "vte_generate_state_changes", +] + +[[package]] +name = "vte_generate_state_changes" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e369bee1b05d510a7b4ed645f5faa90619e05437111783ea5848f28d97d3c2e" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "waker-fn" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.87", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "wasm_dep_analyzer" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f270206a91783fd90625c8bb0d8fbd459d0b1d1bf209b656f713f01ae7c04b8" +dependencies = [ + "thiserror", +] + +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-root-certs" +version = "0.26.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8c6dfa3ac045bc517de14c7b1384298de1dbd229d38e08e169d9ae8c170937c" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "webpki-roots" +version = "0.26.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "wgpu-core" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d50819ab545b867d8a454d1d756b90cd5f15da1f2943334ca314af10583c9d39" +dependencies = [ + "arrayvec", + "bit-vec", + "bitflags 2.6.0", + "cfg_aliases 0.1.1", + "codespan-reporting", + "document-features", + "indexmap 2.6.0", + "log", + "naga", + "once_cell", + "parking_lot", + "profiling", + "raw-window-handle", + "ron", + "rustc-hash", + "serde", + "smallvec", + "thiserror", + "web-sys", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-hal" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "172e490a87295564f3fcc0f165798d87386f6231b04d4548bca458cbbfd63222" +dependencies = [ + "android_system_properties", + "arrayvec", + "ash", + "bit-set", + "bitflags 2.6.0", + "block", + "cfg_aliases 0.1.1", + "core-graphics-types", + "d3d12", + "glow", + "glutin_wgl_sys", + "gpu-alloc", + "gpu-descriptor", + "js-sys", + "khronos-egl", + "libc", + "libloading 0.8.4", + "log", + "metal", + "naga", + "ndk-sys", + "objc", + "once_cell", + "parking_lot", + "profiling", + "range-alloc", + "raw-window-handle", + "rustc-hash", + "smallvec", + "thiserror", + "wasm-bindgen", + "web-sys", + "wgpu-types", + "winapi", +] + +[[package]] +name = "wgpu-types" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1353d9a46bff7f955a680577f34c69122628cc2076e1d6f3a9be6ef00ae793ef" +dependencies = [ + "bitflags 2.6.0", + "js-sys", + "serde", + "web-sys", +] + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + +[[package]] +name = "which" +version = "6.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8211e4f58a2b2805adfbefbc07bab82958fc91e3836339b1ab7ae32465dce0d7" +dependencies = [ + "either", + "home", + "rustix", + "winsafe", +] + +[[package]] +name = "whoami" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44ab49fad634e88f55bf8f9bb3abd2f27d7204172a112c7c9987e01c1c94ea9" +dependencies = [ + "redox_syscall 0.4.1", + "wasite", + "web-sys", +] + +[[package]] +name = "widestring" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.5", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.5", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[package]] +name = "winnow" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "winres" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b68db261ef59e9e52806f688020631e987592bd83619edccda9c47d42cde4f6c" +dependencies = [ + "toml", +] + +[[package]] +name = "winsafe" +version = "0.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" + +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "wtf8" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c01ae8492c38f52376efd3a17d0994b6bcf3df1e39c0226d458b7d81670b2a06" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "x25519-dalek" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" +dependencies = [ + "curve25519-dalek", + "rand_core", + "serde", + "zeroize", +] + +[[package]] +name = "x509-parser" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7069fba5b66b9193bd2c5d3d4ff12b839118f6bcbef5328efafafb5395cf63da" +dependencies = [ + "asn1-rs", + "data-encoding", + "der-parser", + "lazy_static", + "nom 7.1.3", + "oid-registry", + "rusticata-macros", + "thiserror", + "time", +] + +[[package]] +name = "xattr" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" +dependencies = [ + "libc", + "linux-raw-sys", + "rustix", +] + +[[package]] +name = "xml-rs" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193" + +[[package]] +name = "xtask" +version = "0.3.0-rc.1" +dependencies = [ + "clap", + "color-eyre", + "denort", + "once_cell", + "tracing", + "tracing-subscriber", + "tracing-unwrap", +] + +[[package]] +name = "yaml_parser" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17c551c67700672ec050a94d5d917487c0ecd644a12735133df65564779c5b7b" +dependencies = [ + "rowan", + "winnow", +] + +[[package]] +name = "yoke" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", + "synstructure 0.13.1", +] + +[[package]] +name = "zerocopy" +version = "0.7.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "zerofrom" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", + "synstructure 0.13.1", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "zeromq" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a4528179201f6eecf211961a7d3276faa61554c82651ecc66387f68fc3004bd" +dependencies = [ + "async-trait", + "asynchronous-codec", + "bytes", + "crossbeam-queue", + "dashmap", + "futures-channel", + "futures-io", + "futures-task", + "futures-util", + "log", + "num-traits", + "once_cell", + "parking_lot", + "rand", + "regex", + "thiserror", + "tokio", + "tokio-util", + "uuid", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + +[[package]] +name = "zip" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc5e4288ea4057ae23afc69a4472434a87a2495cafce6632fd1c4ec9f5cf3494" +dependencies = [ + "arbitrary", + "crc32fast", + "crossbeam-utils", + "displaydoc", + "flate2", + "indexmap 2.6.0", + "memchr", + "thiserror", +] + +[[package]] +name = "zstd" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "6.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee98ffd0b48ee95e6c5168188e44a54550b1564d9d530ee21d5f0eaed1069581" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.11+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75652c55c0b6f3e6f12eb786fe1bc960396bf05a1eb3bf1f3691c3610ac2e6d4" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000..c3eefa37 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,38 @@ +[workspace] +members = ["src/*"] +exclude = ["src/deno_systems"] +resolver = "2" + +[workspace.package] +version = "0.3.0-rc.1" +edition = "2021" + +[workspace.dependencies] +denort = { path = "src/denort" } +deno = { git = "https://github.com/metatypedev/deno", branch = "v2.1.2-embeddable" } +# needed to get deno_core::op2 working +# WARN: must track version used by deno +deno_core = "=0.323.0" + +educe = "0.6" + +color-eyre = "0.6" +anyhow = "1" +tracing = "0.1" +tracing-subscriber = { version = "0.3", features = [ + "env-filter", + "parking_lot", + "tracing-log" +] } +tracing-unwrap = "1.0" + +once_cell = "1" + +# WARN: version must match on clap in `deno` +clap = "=4.5" +clap_complete = "=4.5.24" + +shadow-rs = "0.36.0" + + +tokio = "1" diff --git a/README.md b/README.md index 70c34cde..c5f884fd 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ghjk -ghjk /gk/ is a programmable runtime manager and an attempt at a successor for [asdf](https://github.com/asdf-vm/asdf). +ghjk /gk/ is a set of tools for managing developer environments and an attempt at a successor for [asdf](https://github.com/asdf-vm/asdf). > ghjk is part of the > [Metatype ecosystem](https://github.com/metatypedev/metatype). Consider @@ -11,9 +11,9 @@ ghjk /gk/ is a programmable runtime manager and an attempt at a successor for [a ## Introduction -ghjk offers a unified abstraction to manage package managers (e.g. cargo, pnpm, poetry), languages runtimes (e.g. nightly rust, node@18, python@latest) and developer tools (e.g. pre-commit, eslint, protoc). It enables you to define a consistent environment across your dev environments, CI/CD pipelines and containers keeping everything well-defined in your repo and providing a great DX. - -ghjk was designed to be an intermediate alternative between [Earthly](https://github.com/earthly/earthly)/[Dagger](https://github.com/dagger/dagger) (lighter and more flexible) and complex building tools like [Bazel](https://github.com/bazelbuild/bazel/)/[Nix-based devenv](https://github.com/cachix/devenv) (simpler and more extensible). This makes it especially convenient for mono-repos and long-lived projects. See [Metatype](https://github.com/metatypedev/metatype) and its [ghjkfile](https://github.com/metatypedev/metatype/blob/main/ghjk.ts) for a real world example. +ghjk offers a unified abstraction to manage package managers (e.g. cargo, pnpm, poetry), languages runtimes (e.g. nightly rust, node@18, python@latest) and developer tools (e.g. pre-commit, eslint, protoc). +It enables you to define a consistent environment across your dev environments, CI/CD pipelines and containers keeping everything well-defined in your repo and providing a great DX. +This makes it especially convenient for mono-repos and long-lived projects. See [Metatype](https://github.com/metatypedev/metatype) and its [ghjkfile](https://github.com/metatypedev/metatype/blob/main/ghjk.ts) for a real world example.

ghjk @@ -21,58 +21,56 @@ ghjk was designed to be an intermediate alternative between [Earthly](https://gi ## Features -- Soft-reproducable developer environments. -- Install posix programs from different backend like npm, pypi, crates.io. -- Tasks written in typescript. -- Run tasks when entering/exiting envs. +- Install standalone posix programs or those found on different backends and registries + - [npm](./ports/npmi.ts) + - [pypi](./ports/pipi.ts) + - [crates.io](./ports/cargobi.ts) + - [TBD] [Github releases](https://github.com/metatypedev/ghjk/issues/79) +- Tasks written in typescript + - Ergonomically powered by [`dax`](https://github.com/dsherret/dax). + - Built on Deno, most dependencies are [an import away](https://docs.deno.com/runtime/fundamentals/modules/#importing-third-party-modules-and-libraries). +- Soft-reproducible posix environments. + - Declaratively compose envs for developer shells, CI and tasks. + - Run tasks when entering/exiting envs. ## Getting started -```bash -# stable -curl -fsSL https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/install.sh | bash -# latest (main) -curl -fsSL https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/install.sh | GHJK_VERSION=main bash/fish/zsh -``` +Before anything, make sure the following programs are available on the system. -In your project, create a configuration file called `ghjk.ts` that look something like: +- git +- tar (preferably GNU tar) +- curl +- unzip +- zstd -```ts -// NOTE: All the calls in your `ghjk.ts` file are ultimately modifying the 'sophon' proxy -// object exported here. -// WARN: always import `hack.ts` file first -export { sophon } from "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/hack.ts"; -import { - install, - task, -} from "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/hack.ts"; -import node from "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/ports/node.ts"; - -// install programs (ports) into your env -install(node({ version: "14.17.0" })); - -// write simple scripts and execute them using -// `$ ghjk x greet` -task("greet", async ($, { argv: [name] }) => { - await $`echo Hello ${name}!`; -}); +Install the ghjk cli using the installer scripts like so: + +```bash +curl -fsSL https://raw.github.com/metatypedev/ghjk/v0.3.0-rc.1/install.sh | bash ``` -Use the following command to then access your environment: +Use the following command to create a starter `ghjk.ts` in your project directory: ```bash -ghjk sync +ghjk init ts ``` ### Environments Ghjk is primarily configured through constructs called "environments" or "envs" for short. -They serve as recipes for making (mostly) reproducable posix shells. +They serve as recipes for making (mostly) reproducible posix shells. ```ts -export { sophon } from "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/hack.ts"; -import * as ghjk from "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/hack.ts"; -import * as ports from "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/ports/mod.ts"; +import { file } from "https://raw.github.com/metatypedev/ghjk/v0.3.0-rc.1/mod.ts"; +// ports are small programs that install sowtware to your envs +import * as ports from "https://raw.github.com/metatypedev/ghjk/v0.3.0-rc.1/ports/mod.ts"; + +const ghjk = file({}); + +// NOTE: `ghjk.ts` files are expected to export this sophon object +// all the functions on the ghjk object are ultimately modifying the 'sophon' proxy +// object exported here. +export const sophon = ghjk.sophon; // top level `install`s go to the `main` env ghjk.install(ports.protoc()); @@ -105,8 +103,10 @@ ghjk.env({ installs: [ports.cargobi({ crateName: "cargo-chef" }), ports.zstd()], }); -// builder syntax is also availaible -ghjk.env("ci").var("CI", "1").install(ports.opentofu_ghrel()); +// builder syntax is also available +ghjk.env("ci") + .var("CI", "1") + .install(ports.opentofu_ghrel()); // each task describes it's own env as well ghjk.task({ @@ -114,93 +114,43 @@ ghjk.task({ inherit: "dev", fn: () => console.log("online"), }); -``` - -Once you've configured your environments: - -- `$ ghjk envs cook $name` to reify and install an environment. -- `$ ghjk envs activate $name` to switch to an environment. -- And **most** usefully, `$ ghjk sync $name` to cook and _then_ activate an - environment. - - If shell is already in the specified env, it only does cooking. - - Make sure to `sync` or `cook` your envs after changes. -- If no `$name` is provided, most of these commands will operate on the default - or currently active environment. - -### Ports - -TBD: this feature is in development. -Look in the [kitchen sink](./examples/kitchen/ghjk.ts) for what's currently implemented. - -### Tasks -TBD: this feature is still in development. -Look in the [tasks example](./examples/tasks/ghjk.ts) for what's currently implemented. - -#### Anonymous tasks - -Tasks that aren't give names cannot be invoked from the CLI. -They can be useful for tasks that are meant to be common dependencies of other tasks. - -### `hack.ts` - -The imports from the `hack.ts` module, while nice and striaght forward to use, hold and modify global state. -Any malicious third-party module your ghjkfile imports will thus be able to access them as well, provided they import the same version of the module. - -```ts -// evil.ts -import { env, task } from "https://.../ghjk/hack.ts"; - -env("trueBase").install(ports.act(), ports.pipi({ packageName: "ruff" })); - -env("test").vars({ DEBUG: 1 }); - -// `stdSecureConfig` is a quick way to make an up to spec `secureConfig`. -export const secureConfig = stdSecureConfig({ - defaultBaseEnv: "trueBase", - defaultEnv: "test", +ghjk.config({ + defaultBaseEnv: "main", + defaultEnv: "main", // by default, nodejs, python and other runtime // ports are not allowed to be used // during the build process of other ports. // Disable this security measure here. - // (More security features inbound!.) enableRuntimes: true, }); ``` -To prevent this scenario, the exports from `hack.ts` inspect the call stack and panic if they detect more than one module using them. -This means if you want to spread your ghjkfile across multiple modules, you'll need to use functions described below. - -> [!CAUTION] -> The panic protections of `hack.ts` described above only work if the module is the first import in your ghjkfile. -> If a malicious script gets imported first, it might be able to modify global primordials and get around them. -> We have more ideas to explore on hardening Ghjk security. -> This _hack_ is only a temporary compromise while Ghjk is in alpha state. - -The `hack.ts` file is only optional though and a more verbose but safe way exists through... +Once you've configured your environments: -```ts -import { file } from "https://.../ghjk/mod.ts"; +- `$ ghjk envs cook $name` to reify and install an environment. +- `$ ghjk envs activate $name` to activate/switch to an environment. +- And **most** usefully, `$ ghjk sync $name` to cook and _then_ activate an + environment. + - Make sure to `sync` or `cook` your envs after changes. +- If no `$name` is provided, most of these commands will operate on the default + or currently active environment. -const ghjk = file({ - // items from `config()` are availaible here - defaultEnv: "dev", +More details can be found in the [user manual](./docs/manual.md). - // can even directly add installs, tasks and envs here - installs: [], -}); +## Development -// we still need this export for this file to be a valid ghjkfile -export const sophon = ghjk.sophon; +Use the following command to enter a shell where the ghjk CLI is based on the code that's in the working tree. +This will setup a separate installation at `.dev`. -// the builder functions are also accessible here -const { install, env, task, config } = ghjk; +```bash +$ deno task dev bash/fish/zsh ``` -If you intend on using un-trusted third-party scripts in your ghjk, it's recommended you avoid `hack.ts`. - -## Development +Run the tests in the repository through the deno task: ```bash -$ cat install.sh | GHJK_INSTALLER_URL=$(pwd)/install.ts bash/fish/zsh +$ deno task test +# this supports filtering +$ deno task test --filter envHooks ``` diff --git a/deno.jsonc b/deno.jsonc index 65dde402..b2f858e2 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -1,10 +1,10 @@ { "tasks": { - "test": "deno test --parallel --unstable-worker-options --unstable-kv -A tests/*", - "self": "deno run -A --unstable-kv --unstable-worker-options main.ts ", + "test": "cargo build -p ghjk && deno test --unstable-worker-options --unstable-kv -A tests/*", + "self": "cargo run -p ghjk", "cache": "deno cache deps/*", - "check": "deno run -A ./scripts/check.ts", - "dev": "deno run -A ./scripts/dev.ts" + "check": "deno run -A ./tools/check.ts", + "dev": "deno run -A ./tools/dev.ts" }, "fmt": { "exclude": [ @@ -14,7 +14,8 @@ "**/*.md", ".ghjk/**", ".deno-dir/**", - "vendor/**" + "vendor/**", + "./target/" ] }, "lint": { @@ -24,7 +25,8 @@ ".deno-dir/**", "ghjk.ts", "play.ts", - "vendor/**" + "vendor/**", + "./target/" ], "rules": { "include": [ diff --git a/deno.lock b/deno.lock index 53455e8e..840393da 100644 --- a/deno.lock +++ b/deno.lock @@ -1,287 +1,98 @@ { - "version": "3", - "packages": { - "specifiers": { - "jsr:@david/dax@0.40.1": "jsr:@david/dax@0.40.1", - "jsr:@david/dax@0.41.0": "jsr:@david/dax@0.41.0", - "jsr:@david/which@0.3": "jsr:@david/which@0.3.0", - "jsr:@david/which@^0.4.1": "jsr:@david/which@0.4.1", - "jsr:@ghjk/dax@0.40.2-alpha-ghjk": "jsr:@ghjk/dax@0.40.2-alpha-ghjk", - "jsr:@std/assert@^0.221.0": "jsr:@std/assert@0.221.0", - "jsr:@std/bytes@^0.221.0": "jsr:@std/bytes@0.221.0", - "jsr:@std/fmt@^0.221.0": "jsr:@std/fmt@0.221.0", - "jsr:@std/fs@0.221.0": "jsr:@std/fs@0.221.0", - "jsr:@std/io@0.221.0": "jsr:@std/io@0.221.0", - "jsr:@std/io@^0.221.0": "jsr:@std/io@0.221.0", - "jsr:@std/path@0.221.0": "jsr:@std/path@0.221.0", - "jsr:@std/path@^0.221.0": "jsr:@std/path@0.221.0", - "jsr:@std/streams@0.221.0": "jsr:@std/streams@0.221.0", - "npm:@noble/hashes@1.4.0": "npm:@noble/hashes@1.4.0", - "npm:@types/node": "npm:@types/node@18.16.19", - "npm:lodash": "npm:lodash@4.17.21", - "npm:mathjs@11.11.1": "npm:mathjs@11.11.1", - "npm:multiformats@13.1.0": "npm:multiformats@13.1.0", - "npm:pg": "npm:pg@8.12.0", - "npm:validator": "npm:validator@13.12.0", - "npm:zod-validation-error": "npm:zod-validation-error@3.1.0_zod@3.23.3", - "npm:zod-validation-error@3.2.0": "npm:zod-validation-error@3.2.0_zod@3.23.3", - "npm:zod-validation-error@3.3.0": "npm:zod-validation-error@3.3.0_zod@3.23.3", - "npm:zod@3.23.8": "npm:zod@3.23.8" + "version": "4", + "specifiers": { + "jsr:@david/dax@0.41.0": "0.41.0", + "jsr:@david/which@~0.4.1": "0.4.1", + "jsr:@std/assert@0.221": "0.221.0", + "jsr:@std/bytes@0.221": "0.221.0", + "jsr:@std/fmt@0.221": "0.221.0", + "jsr:@std/fs@0.221.0": "0.221.0", + "jsr:@std/io@0.221": "0.221.0", + "jsr:@std/io@0.221.0": "0.221.0", + "jsr:@std/path@0.221": "0.221.0", + "jsr:@std/path@0.221.0": "0.221.0", + "jsr:@std/streams@0.221.0": "0.221.0", + "npm:@noble/hashes@1.4.0": "1.4.0", + "npm:@types/node@*": "22.5.4", + "npm:multiformats@13.1.0": "13.1.0", + "npm:zod-validation-error@3.4.0": "3.4.0_zod@3.23.8", + "npm:zod@3.23.8": "3.23.8" + }, + "jsr": { + "@david/dax@0.41.0": { + "integrity": "9e1ecf66a0415962cc8ad3ba4e3fa93ce0f1a1cc797dd95c36fdfb6977dc7fc8", + "dependencies": [ + "jsr:@david/which", + "jsr:@std/fmt", + "jsr:@std/fs", + "jsr:@std/io@0.221.0", + "jsr:@std/path@0.221.0", + "jsr:@std/streams" + ] + }, + "@david/which@0.4.1": { + "integrity": "896a682b111f92ab866cc70c5b4afab2f5899d2f9bde31ed00203b9c250f225e" + }, + "@std/assert@0.221.0": { + "integrity": "a5f1aa6e7909dbea271754fd4ab3f4e687aeff4873b4cef9a320af813adb489a" + }, + "@std/bytes@0.221.0": { + "integrity": "64a047011cf833890a4a2ab7293ac55a1b4f5a050624ebc6a0159c357de91966" + }, + "@std/fmt@0.221.0": { + "integrity": "379fed69bdd9731110f26b9085aeb740606b20428ce6af31ef6bd45ef8efa62a" + }, + "@std/fs@0.221.0": { + "integrity": "028044450299de8ed5a716ade4e6d524399f035513b85913794f4e81f07da286", + "dependencies": [ + "jsr:@std/assert", + "jsr:@std/path@0.221" + ] + }, + "@std/io@0.221.0": { + "integrity": "faf7f8700d46ab527fa05cc6167f4b97701a06c413024431c6b4d207caa010da", + "dependencies": [ + "jsr:@std/assert", + "jsr:@std/bytes" + ] + }, + "@std/path@0.221.0": { + "integrity": "0a36f6b17314ef653a3a1649740cc8db51b25a133ecfe838f20b79a56ebe0095", + "dependencies": [ + "jsr:@std/assert" + ] + }, + "@std/streams@0.221.0": { + "integrity": "47f2f74634b47449277c0ee79fe878da4424b66bd8975c032e3afdca88986e61", + "dependencies": [ + "jsr:@std/io@0.221" + ] + } + }, + "npm": { + "@noble/hashes@1.4.0": { + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==" + }, + "@types/node@22.5.4": { + "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==", + "dependencies": [ + "undici-types" + ] + }, + "multiformats@13.1.0": { + "integrity": "sha512-HzdtdBwxsIkzpeXzhQ5mAhhuxcHbjEHH+JQoxt7hG/2HGFjjwyolLo7hbaexcnhoEuV4e0TNJ8kkpMjiEYY4VQ==" + }, + "undici-types@6.19.8": { + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==" }, - "jsr": { - "@david/dax@0.40.1": { - "integrity": "0c71d32a0484d3904f586417995f8ec26d45144f0eba95d3e5bb03b640b6df59", - "dependencies": [ - "jsr:@david/which@0.3", - "jsr:@std/fmt@^0.221.0", - "jsr:@std/fs@0.221.0", - "jsr:@std/io@0.221.0", - "jsr:@std/path@0.221.0", - "jsr:@std/streams@0.221.0" - ] - }, - "@david/dax@0.41.0": { - "integrity": "9e1ecf66a0415962cc8ad3ba4e3fa93ce0f1a1cc797dd95c36fdfb6977dc7fc8", - "dependencies": [ - "jsr:@david/which@^0.4.1", - "jsr:@std/fmt@^0.221.0", - "jsr:@std/fs@0.221.0", - "jsr:@std/io@0.221.0", - "jsr:@std/path@0.221.0", - "jsr:@std/streams@0.221.0" - ] - }, - "@david/which@0.3.0": { - "integrity": "6bdb62c40ac90edcf328e854fa8103a8db21e7c326089cbe3c3a1cf7887d3204" - }, - "@david/which@0.4.1": { - "integrity": "896a682b111f92ab866cc70c5b4afab2f5899d2f9bde31ed00203b9c250f225e" - }, - "@ghjk/dax@0.40.2-alpha-ghjk": { - "integrity": "87bc93e9947779cb2f3922fe277e21ea8c716de804b2627f80ba9e7bc3d0d019", - "dependencies": [ - "jsr:@david/which@0.3", - "jsr:@std/fmt@^0.221.0", - "jsr:@std/fs@0.221.0", - "jsr:@std/io@0.221.0", - "jsr:@std/path@0.221.0", - "jsr:@std/streams@0.221.0" - ] - }, - "@std/assert@0.221.0": { - "integrity": "a5f1aa6e7909dbea271754fd4ab3f4e687aeff4873b4cef9a320af813adb489a" - }, - "@std/bytes@0.221.0": { - "integrity": "64a047011cf833890a4a2ab7293ac55a1b4f5a050624ebc6a0159c357de91966" - }, - "@std/fmt@0.221.0": { - "integrity": "379fed69bdd9731110f26b9085aeb740606b20428ce6af31ef6bd45ef8efa62a" - }, - "@std/fs@0.221.0": { - "integrity": "028044450299de8ed5a716ade4e6d524399f035513b85913794f4e81f07da286", - "dependencies": [ - "jsr:@std/assert@^0.221.0", - "jsr:@std/path@^0.221.0" - ] - }, - "@std/io@0.221.0": { - "integrity": "faf7f8700d46ab527fa05cc6167f4b97701a06c413024431c6b4d207caa010da", - "dependencies": [ - "jsr:@std/assert@^0.221.0", - "jsr:@std/bytes@^0.221.0" - ] - }, - "@std/path@0.221.0": { - "integrity": "0a36f6b17314ef653a3a1649740cc8db51b25a133ecfe838f20b79a56ebe0095", - "dependencies": [ - "jsr:@std/assert@^0.221.0" - ] - }, - "@std/streams@0.221.0": { - "integrity": "47f2f74634b47449277c0ee79fe878da4424b66bd8975c032e3afdca88986e61", - "dependencies": [ - "jsr:@std/io@^0.221.0" - ] - } + "zod-validation-error@3.4.0_zod@3.23.8": { + "integrity": "sha512-ZOPR9SVY6Pb2qqO5XHt+MkkTRxGXb4EVtnjc9JpXUOtUB1T9Ru7mZOT361AN3MsetVe7R0a1KZshJDZdgp9miQ==", + "dependencies": [ + "zod" + ] }, - "npm": { - "@babel/runtime@7.24.7": { - "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==", - "dependencies": { - "regenerator-runtime": "regenerator-runtime@0.14.1" - } - }, - "@noble/hashes@1.4.0": { - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "dependencies": {} - }, - "@types/node@18.16.19": { - "integrity": "sha512-IXl7o+R9iti9eBW4Wg2hx1xQDig183jj7YLn8F7udNceyfkbn1ZxmzZXuak20gR40D7pIkIY1kYGx5VIGbaHKA==", - "dependencies": {} - }, - "complex.js@2.1.1": { - "integrity": "sha512-8njCHOTtFFLtegk6zQo0kkVX1rngygb/KQI6z1qZxlFI3scluC+LVTCFbrkWjBv4vvLlbQ9t88IPMC6k95VTTg==", - "dependencies": {} - }, - "decimal.js@10.4.3": { - "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", - "dependencies": {} - }, - "escape-latex@1.2.0": { - "integrity": "sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw==", - "dependencies": {} - }, - "fraction.js@4.3.4": { - "integrity": "sha512-pwiTgt0Q7t+GHZA4yaLjObx4vXmmdcS0iSJ19o8d/goUGgItX9UZWKWNnLHehxviD8wU2IWRsnR8cD5+yOJP2Q==", - "dependencies": {} - }, - "javascript-natural-sort@0.7.1": { - "integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==", - "dependencies": {} - }, - "lodash@4.17.21": { - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dependencies": {} - }, - "mathjs@11.11.1": { - "integrity": "sha512-uWrwMrhU31TCqHKmm1yFz0C352njGUVr/I1UnpMOxI/VBTTbCktx/mREUXx5Vyg11xrFdg/F3wnMM7Ql/csVsQ==", - "dependencies": { - "@babel/runtime": "@babel/runtime@7.24.7", - "complex.js": "complex.js@2.1.1", - "decimal.js": "decimal.js@10.4.3", - "escape-latex": "escape-latex@1.2.0", - "fraction.js": "fraction.js@4.3.4", - "javascript-natural-sort": "javascript-natural-sort@0.7.1", - "seedrandom": "seedrandom@3.0.5", - "tiny-emitter": "tiny-emitter@2.1.0", - "typed-function": "typed-function@4.2.1" - } - }, - "multiformats@13.1.0": { - "integrity": "sha512-HzdtdBwxsIkzpeXzhQ5mAhhuxcHbjEHH+JQoxt7hG/2HGFjjwyolLo7hbaexcnhoEuV4e0TNJ8kkpMjiEYY4VQ==", - "dependencies": {} - }, - "pg-cloudflare@1.1.1": { - "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", - "dependencies": {} - }, - "pg-connection-string@2.6.4": { - "integrity": "sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA==", - "dependencies": {} - }, - "pg-int8@1.0.1": { - "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", - "dependencies": {} - }, - "pg-pool@3.6.2_pg@8.12.0": { - "integrity": "sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg==", - "dependencies": { - "pg": "pg@8.12.0" - } - }, - "pg-protocol@1.6.1": { - "integrity": "sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg==", - "dependencies": {} - }, - "pg-types@2.2.0": { - "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", - "dependencies": { - "pg-int8": "pg-int8@1.0.1", - "postgres-array": "postgres-array@2.0.0", - "postgres-bytea": "postgres-bytea@1.0.0", - "postgres-date": "postgres-date@1.0.7", - "postgres-interval": "postgres-interval@1.2.0" - } - }, - "pg@8.12.0": { - "integrity": "sha512-A+LHUSnwnxrnL/tZ+OLfqR1SxLN3c/pgDztZ47Rpbsd4jUytsTtwQo/TLPRzPJMp/1pbhYVhH9cuSZLAajNfjQ==", - "dependencies": { - "pg-cloudflare": "pg-cloudflare@1.1.1", - "pg-connection-string": "pg-connection-string@2.6.4", - "pg-pool": "pg-pool@3.6.2_pg@8.12.0", - "pg-protocol": "pg-protocol@1.6.1", - "pg-types": "pg-types@2.2.0", - "pgpass": "pgpass@1.0.5" - } - }, - "pgpass@1.0.5": { - "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", - "dependencies": { - "split2": "split2@4.2.0" - } - }, - "postgres-array@2.0.0": { - "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", - "dependencies": {} - }, - "postgres-bytea@1.0.0": { - "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", - "dependencies": {} - }, - "postgres-date@1.0.7": { - "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", - "dependencies": {} - }, - "postgres-interval@1.2.0": { - "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", - "dependencies": { - "xtend": "xtend@4.0.2" - } - }, - "regenerator-runtime@0.14.1": { - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "dependencies": {} - }, - "seedrandom@3.0.5": { - "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==", - "dependencies": {} - }, - "split2@4.2.0": { - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", - "dependencies": {} - }, - "tiny-emitter@2.1.0": { - "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==", - "dependencies": {} - }, - "typed-function@4.2.1": { - "integrity": "sha512-EGjWssW7Tsk4DGfE+5yluuljS1OGYWiI1J6e8puZz9nTMM51Oug8CD5Zo4gWMsOhq5BI+1bF+rWTm4Vbj3ivRA==", - "dependencies": {} - }, - "validator@13.12.0": { - "integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==", - "dependencies": {} - }, - "xtend@4.0.2": { - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dependencies": {} - }, - "zod-validation-error@3.1.0_zod@3.23.3": { - "integrity": "sha512-zujS6HqJjMZCsvjfbnRs7WI3PXN39ovTcY1n8a+KTm4kOH0ZXYsNiJkH1odZf4xZKMkBDL7M2rmQ913FCS1p9w==", - "dependencies": { - "zod": "zod@3.23.3" - } - }, - "zod-validation-error@3.2.0_zod@3.23.3": { - "integrity": "sha512-cYlPR6zuyrgmu2wRTdumEAJGuwI7eHVHGT+VyneAQxmRAKtGRL1/7pjz4wfLhz4J05f5qoSZc3rGacswgyTjjw==", - "dependencies": { - "zod": "zod@3.23.3" - } - }, - "zod-validation-error@3.3.0_zod@3.23.3": { - "integrity": "sha512-Syib9oumw1NTqEv4LT0e6U83Td9aVRk9iTXPUQr1otyV1PuXQKOvOwhMNqZIq5hluzHP2pMgnOmHEo7kPdI2mw==", - "dependencies": { - "zod": "zod@3.23.3" - } - }, - "zod@3.23.3": { - "integrity": "sha512-tPvq1B/2Yu/dh2uAIH2/BhUlUeLIUvAjr6dpL/75I0pCYefHgjhXk1o1Kob3kTU8C7yU1j396jFHlsVWFi9ogg==", - "dependencies": {} - }, - "zod@3.23.8": { - "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", - "dependencies": {} - } + "zod@3.23.8": { + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==" } }, "remote": { @@ -297,12 +108,17 @@ "https://deno.land/std@0.116.0/path/posix.ts": "34349174b9cd121625a2810837a82dd8b986bbaaad5ade690d1de75bbb4555b2", "https://deno.land/std@0.116.0/path/separator.ts": "8fdcf289b1b76fd726a508f57d3370ca029ae6976fcde5044007f062e643ff1c", "https://deno.land/std@0.116.0/path/win32.ts": "11549e8c6df8307a8efcfa47ad7b2a75da743eac7d4c89c9723a944661c8bd2e", - "https://deno.land/std@0.120.0/_wasm_crypto/crypto.js": "5c283a80e1059d16589b79fa026be5fb0a28424302a99487cadceef8c17f8afa", - "https://deno.land/std@0.120.0/_wasm_crypto/crypto.wasm.js": "0e6df3c18beb1187b442ec7f0a03df4d18b21212172d6b4a50ee4816404771d7", - "https://deno.land/std@0.120.0/_wasm_crypto/mod.ts": "7d02009ef3ddc953c8f90561d213e02fa0a6f3eaed9b8baf0c241c8cbeec1ed3", - "https://deno.land/std@0.120.0/crypto/mod.ts": "5760510eaa0b250f78cce81ce92d83cf8c40e9bb3c3efeedd4ef1a5bb0801ef4", - "https://deno.land/std@0.120.0/encoding/ascii85.ts": "b42b041e9c668afa356dd07ccf69a6b3ee49b9ae080fdf3b03f0ac3981f4d1e6", - "https://deno.land/std@0.120.0/encoding/base64.ts": "0b58bd6477214838bf711eef43eac21e47ba9e5c81b2ce185fe25d9ecab3ebb3", + "https://deno.land/std@0.134.0/_util/assert.ts": "e94f2eb37cebd7f199952e242c77654e43333c1ac4c5c700e929ea3aa5489f74", + "https://deno.land/std@0.134.0/_util/os.ts": "49b92edea1e82ba295ec946de8ffd956ed123e2948d9bd1d3e901b04e4307617", + "https://deno.land/std@0.134.0/path/_constants.ts": "df1db3ffa6dd6d1252cc9617e5d72165cd2483df90e93833e13580687b6083c3", + "https://deno.land/std@0.134.0/path/_interface.ts": "ee3b431a336b80cf445441109d089b70d87d5e248f4f90ff906820889ecf8d09", + "https://deno.land/std@0.134.0/path/_util.ts": "c1e9686d0164e29f7d880b2158971d805b6e0efc3110d0b3e24e4b8af2190d2b", + "https://deno.land/std@0.134.0/path/common.ts": "bee563630abd2d97f99d83c96c2fa0cca7cee103e8cb4e7699ec4d5db7bd2633", + "https://deno.land/std@0.134.0/path/glob.ts": "cb5255638de1048973c3e69e420c77dc04f75755524cb3b2e160fe9277d939ee", + "https://deno.land/std@0.134.0/path/mod.ts": "4275129bb766f0e475ecc5246aa35689eeade419d72a48355203f31802640be7", + "https://deno.land/std@0.134.0/path/posix.ts": "663e4a6fe30a145f56aa41a22d95114c4c5582d8b57d2d7c9ed27ad2c47636bb", + "https://deno.land/std@0.134.0/path/separator.ts": "fe1816cb765a8068afb3e8f13ad272351c85cbc739af56dacfc7d93d710fe0f9", + "https://deno.land/std@0.134.0/path/win32.ts": "e7bdf63e8d9982b4d8a01ef5689425c93310ece950e517476e22af10f41a136e", "https://deno.land/std@0.213.0/archive/_common.ts": "85edd5cdd4324833f613c1bc055f8e2f935cc9229c6b3044421268d9959997ef", "https://deno.land/std@0.213.0/archive/untar.ts": "7677c136f2188cd8c33363ccaaee6e77d4ca656cca3e2093d08de8f294d4353d", "https://deno.land/std@0.213.0/assert/_constants.ts": "a271e8ef5a573f1df8e822a6eb9d09df064ad66a4390f21b3e31f820a38e0975", @@ -559,12 +375,6 @@ "https://deno.land/std@0.213.0/url/join.ts": "00c7e9088cafaa24963ce4081119e58b3afe2c58f033701383f359ea02620dd2", "https://deno.land/std@0.213.0/url/mod.ts": "e2621f6a0db6fdbe7fbbd240064095bb203014657e5e1ab81db1c44d80dce6c9", "https://deno.land/std@0.213.0/url/normalize.ts": "6328c75df0fab300f74bc4a1c255062a0db882240e15ab646606d0009e7e40d7", - "https://deno.land/std@0.219.0/assert/assert.ts": "bec068b2fccdd434c138a555b19a2c2393b71dfaada02b7d568a01541e67cdc5", - "https://deno.land/std@0.219.0/assert/assertion_error.ts": "9f689a101ee586c4ce92f52fa7ddd362e86434ffdf1f848e45987dc7689976b8", - "https://deno.land/std@0.219.0/cli/mod.ts": "58f75df8ce43fb8266bdd26ec4465f73176b910316d72eb8e090b6a0549391da", - "https://deno.land/std@0.219.0/cli/parse_args.ts": "475b3edc8105c9acea09b83b100afc383d7bddbba9828da3f0c4adced006607a", - "https://deno.land/std@0.219.0/cli/prompt_secret.ts": "831cfb4efa83bfaf9bfd320ddbfd619e03cd87e81260909f93ca199ebe214ec2", - "https://deno.land/std@0.219.0/cli/spinner.ts": "005395c4e00b1086bfa2ae44e8c9413c1231c4741a08a55aa0d3c9ea267cecb5", "https://deno.land/std@0.221.0/assert/assert.ts": "bec068b2fccdd434c138a555b19a2c2393b71dfaada02b7d568a01541e67cdc5", "https://deno.land/std@0.221.0/assert/assertion_error.ts": "9f689a101ee586c4ce92f52fa7ddd362e86434ffdf1f848e45987dc7689976b8", "https://deno.land/std@0.221.0/console/_data.json": "cf2cc9d039a192b3adbfe64627167c7e6212704c888c25c769fc8f1709e1e1b8", @@ -573,12 +383,6 @@ "https://deno.land/std@0.221.0/fmt/colors.ts": "d239d84620b921ea520125d778947881f62c50e78deef2657073840b8af9559a", "https://deno.land/std@0.221.0/text/closest_string.ts": "8a91ee8b6d69ff96addcb7c251dad53b476ac8be9c756a0ef786abe9e13a93a5", "https://deno.land/std@0.221.0/text/levenshtein_distance.ts": "24be5cc88326bbba83ca7c1ea89259af0050cffda2817ff3a6d240ad6495eae2", - "https://deno.land/std@0.76.0/encoding/base64.ts": "b1d8f99b778981548457ec74bc6273ad785ffd6f61b2233bd5b30925345b565d", - "https://deno.land/std@0.76.0/encoding/hex.ts": "07a03ba41c96060a4ed4ba272e50b9e23f3c5b3839f4b069cdebc24d57434386", - "https://deno.land/std@0.76.0/hash/_wasm/hash.ts": "005f64c4d9343ecbc91e0da9ae5e800f146c20930ad829bbb872c5c06bd89c5f", - "https://deno.land/std@0.76.0/hash/_wasm/wasm.js": "5ac48aa0c3931d7f31dba628be5ab0aa4e786354197eb4d7d0583f9b50be1397", - "https://deno.land/std@0.76.0/hash/hasher.ts": "099c9e2a91b9f106b9f01379705e17e7d9de392ee1ea2b8684a2adfa82ac3bfc", - "https://deno.land/std@0.76.0/hash/mod.ts": "e764a6a9ab2f5519a97f928e17cc13d984e3dd5c7f742ff9c1c8fb3114790f0c", "https://deno.land/x/cliffy@v1.0.0-rc.4/command/_argument_types.ts": "ab269dacea2030f865a07c2a1e953ec437a64419a05bad1f1ddaab3f99752ead", "https://deno.land/x/cliffy@v1.0.0-rc.4/command/_errors.ts": "d78e1b4d69d84b8b476b5f3c0b028e3906d48f21b8f1ca1d36d5abe9ccfe48bc", "https://deno.land/x/cliffy@v1.0.0-rc.4/command/_spread.ts": "0cc6eb70a6df97b5d7d26008822d39f3e8a1232ee0a27f395aa19e68de738245", @@ -644,56 +448,16 @@ "https://deno.land/x/foras@v2.1.4/wasm/pkg/foras.js": "06f8875b456918b9671d52133f64f3047f1c95540feda87fdd4a55ba3d30091d", "https://deno.land/x/foras@v2.1.4/wasm/pkg/foras.wasm.js": "2df8522df7243b0f05b1d188e220629cd5d2c92080a5f1407e15396fc35bebb3", "https://deno.land/x/json_hash@0.2.0/canon.ts": "ce7c07abd871cd7f0eb1280ad9f58f6382f02f84a217898ce977cf35ad315877", - "https://deno.land/x/json_hash@0.2.0/crypto.ts": "8738b601a0cf52c0ff58242707e2d5f7f5ff8f7ca4d51d0282ad3b0bb56548cf", - "https://deno.land/x/json_hash@0.2.0/digest.ts": "95e3d996377eebebb960ad2b6e4fdd70d71543378a651c31de75f1e86b637fc7", - "https://deno.land/x/json_hash@0.2.0/hex.ts": "104154a6408c6b5b36ff35361011aeb3047941bd5a652724f5aebeeb89fcf9a8", - "https://deno.land/x/json_hash@0.2.0/merkle.ts": "cf48004b45fdf0412afd48fea0ba8bb16bf78f717a66a5ff505f6400a88c08cf", - "https://deno.land/x/json_hash@0.2.0/mod.ts": "b0fdd79a540d3fc6aa3e0a9a93fe6735b1a174d9ba2aba103e4a18ee4872acad", "https://deno.land/x/jszip@0.11.0/mod.ts": "5661ddc18e9ac9c07e3c5d2483bc912a7022b6af0d784bb7b05035973e640ba1", "https://deno.land/x/jszip@0.11.0/types.ts": "1528d1279fbb64dd118c371331c641a3a5eff2b594336fb38a7659cf4c53b2d1", - "https://deno.land/x/object_hash@2.0.3.1/index.ts": "74b20a0065dc0066c60510174626db1d18e53ec966edb6f76fa33a67aa0c44e3", - "https://deno.land/x/object_hash@2.0.3.1/mod.ts": "648559bcafb54b930d4b6a283cc2eef20afa54de471371a97c2ccf8116941148", - "https://deno.land/x/object_hash@2.0.3/index.ts": "74b20a0065dc0066c60510174626db1d18e53ec966edb6f76fa33a67aa0c44e3", - "https://deno.land/x/object_hash@2.0.3/mod.ts": "648559bcafb54b930d4b6a283cc2eef20afa54de471371a97c2ccf8116941148", - "https://deno.land/x/zod@v3.22.4/ZodError.ts": "4de18ff525e75a0315f2c12066b77b5c2ae18c7c15ef7df7e165d63536fdf2ea", - "https://deno.land/x/zod@v3.22.4/errors.ts": "5285922d2be9700cc0c70c95e4858952b07ae193aa0224be3cbd5cd5567eabef", - "https://deno.land/x/zod@v3.22.4/external.ts": "a6cfbd61e9e097d5f42f8a7ed6f92f93f51ff927d29c9fbaec04f03cbce130fe", - "https://deno.land/x/zod@v3.22.4/helpers/enumUtil.ts": "54efc393cc9860e687d8b81ff52e980def00fa67377ad0bf8b3104f8a5bf698c", - "https://deno.land/x/zod@v3.22.4/helpers/errorUtil.ts": "7a77328240be7b847af6de9189963bd9f79cab32bbc61502a9db4fe6683e2ea7", - "https://deno.land/x/zod@v3.22.4/helpers/parseUtil.ts": "f791e6e65a0340d85ad37d26cd7a3ba67126cd9957eac2b7163162155283abb1", - "https://deno.land/x/zod@v3.22.4/helpers/partialUtil.ts": "998c2fe79795257d4d1cf10361e74492f3b7d852f61057c7c08ac0a46488b7e7", - "https://deno.land/x/zod@v3.22.4/helpers/typeAliases.ts": "0fda31a063c6736fc3cf9090dd94865c811dfff4f3cb8707b932bf937c6f2c3e", - "https://deno.land/x/zod@v3.22.4/helpers/util.ts": "8baf19b19b2fca8424380367b90364b32503b6b71780269a6e3e67700bb02774", - "https://deno.land/x/zod@v3.22.4/index.ts": "d27aabd973613985574bc31f39e45cb5d856aa122ef094a9f38a463b8ef1a268", - "https://deno.land/x/zod@v3.22.4/locales/en.ts": "a7a25cd23563ccb5e0eed214d9b31846305ddbcdb9c5c8f508b108943366ab4c", - "https://deno.land/x/zod@v3.22.4/mod.ts": "64e55237cb4410e17d968cd08975566059f27638ebb0b86048031b987ba251c4", - "https://deno.land/x/zod@v3.22.4/types.ts": "724185522fafe43ee56a52333958764c8c8cd6ad4effa27b42651df873fc151e", - "https://deno.land/x/zod@v3.23.5/ZodError.ts": "528da200fbe995157b9ae91498b103c4ef482217a5c086249507ac850bd78f52", - "https://deno.land/x/zod@v3.23.5/errors.ts": "5285922d2be9700cc0c70c95e4858952b07ae193aa0224be3cbd5cd5567eabef", - "https://deno.land/x/zod@v3.23.5/external.ts": "a6cfbd61e9e097d5f42f8a7ed6f92f93f51ff927d29c9fbaec04f03cbce130fe", - "https://deno.land/x/zod@v3.23.5/helpers/enumUtil.ts": "54efc393cc9860e687d8b81ff52e980def00fa67377ad0bf8b3104f8a5bf698c", - "https://deno.land/x/zod@v3.23.5/helpers/errorUtil.ts": "7a77328240be7b847af6de9189963bd9f79cab32bbc61502a9db4fe6683e2ea7", - "https://deno.land/x/zod@v3.23.5/helpers/parseUtil.ts": "c14814d167cc286972b6e094df88d7d982572a08424b7cd50f862036b6fcaa77", - "https://deno.land/x/zod@v3.23.5/helpers/partialUtil.ts": "998c2fe79795257d4d1cf10361e74492f3b7d852f61057c7c08ac0a46488b7e7", - "https://deno.land/x/zod@v3.23.5/helpers/typeAliases.ts": "0fda31a063c6736fc3cf9090dd94865c811dfff4f3cb8707b932bf937c6f2c3e", - "https://deno.land/x/zod@v3.23.5/helpers/util.ts": "3301a69867c9e589ac5b3bc4d7a518b5212858cd6a25e8b02d635c9c32ba331c", - "https://deno.land/x/zod@v3.23.5/index.ts": "d27aabd973613985574bc31f39e45cb5d856aa122ef094a9f38a463b8ef1a268", - "https://deno.land/x/zod@v3.23.5/locales/en.ts": "a7a25cd23563ccb5e0eed214d9b31846305ddbcdb9c5c8f508b108943366ab4c", - "https://deno.land/x/zod@v3.23.5/mod.ts": "ec6e2b1255c1a350b80188f97bd0a6bac45801bb46fc48f50b9763aa66046039", - "https://deno.land/x/zod@v3.23.5/types.ts": "78d3f06eb313ea754fad0ee389d3c0fa55bc01cf708e6ce0ea7fddd41f31eca2", - "https://deno.land/x/zod@v3.23.8/ZodError.ts": "528da200fbe995157b9ae91498b103c4ef482217a5c086249507ac850bd78f52", - "https://deno.land/x/zod@v3.23.8/errors.ts": "5285922d2be9700cc0c70c95e4858952b07ae193aa0224be3cbd5cd5567eabef", - "https://deno.land/x/zod@v3.23.8/external.ts": "a6cfbd61e9e097d5f42f8a7ed6f92f93f51ff927d29c9fbaec04f03cbce130fe", - "https://deno.land/x/zod@v3.23.8/helpers/enumUtil.ts": "54efc393cc9860e687d8b81ff52e980def00fa67377ad0bf8b3104f8a5bf698c", - "https://deno.land/x/zod@v3.23.8/helpers/errorUtil.ts": "7a77328240be7b847af6de9189963bd9f79cab32bbc61502a9db4fe6683e2ea7", - "https://deno.land/x/zod@v3.23.8/helpers/parseUtil.ts": "c14814d167cc286972b6e094df88d7d982572a08424b7cd50f862036b6fcaa77", - "https://deno.land/x/zod@v3.23.8/helpers/partialUtil.ts": "998c2fe79795257d4d1cf10361e74492f3b7d852f61057c7c08ac0a46488b7e7", - "https://deno.land/x/zod@v3.23.8/helpers/typeAliases.ts": "0fda31a063c6736fc3cf9090dd94865c811dfff4f3cb8707b932bf937c6f2c3e", - "https://deno.land/x/zod@v3.23.8/helpers/util.ts": "30c273131661ca5dc973f2cfb196fa23caf3a43e224cdde7a683b72e101a31fc", - "https://deno.land/x/zod@v3.23.8/index.ts": "d27aabd973613985574bc31f39e45cb5d856aa122ef094a9f38a463b8ef1a268", - "https://deno.land/x/zod@v3.23.8/locales/en.ts": "a7a25cd23563ccb5e0eed214d9b31846305ddbcdb9c5c8f508b108943366ab4c", - "https://deno.land/x/zod@v3.23.8/mod.ts": "ec6e2b1255c1a350b80188f97bd0a6bac45801bb46fc48f50b9763aa66046039", - "https://deno.land/x/zod@v3.23.8/types.ts": "1b172c90782b1eaa837100ebb6abd726d79d6c1ec336350c8e851e0fd706bf5c", + "https://deno.land/x/os_paths@v7.2.0/dist/esm/lib/OSPaths.js": "db4f5f05765a1c862e7b1e0f0c293fc752e94e213eabff19f3c03af9b2164f98", + "https://deno.land/x/os_paths@v7.2.0/src/mod.deno.ts": "5e34d7c1a033665276a1a06e3957a52218bf4711a801f38cf92978aacfad5666", + "https://deno.land/x/os_paths@v7.2.0/src/platform-adapters/_base.ts": "ca9adf679709824e070631921932620ab4dc2a39fff9706f95592d1620e34dc6", + "https://deno.land/x/os_paths@v7.2.0/src/platform-adapters/deno.deno.ts": "d184d709522bf2703dc12ff335eb6a10d758a3a5dd4d97524d2aef9d3d448c13", + "https://deno.land/x/xdg_portable@v10.6.0/dist/esm/lib/XDG.js": "4c04a45149d66e4ca29ea914aac137e7b0f0b6a8ef431ffc63fef46bc3747064", + "https://deno.land/x/xdg_portable@v10.6.0/src/mod.deno.ts": "e478cc109794bfc130ec81711f9a20d594e6fad848f796c68b75dbe510683c39", + "https://deno.land/x/xdg_portable@v10.6.0/src/platform-adapters/_base.ts": "c79a7f0e5b1d77e23cbc6c782a02958573338e9dfa644a7aa5a1f7c402ff56ef", + "https://deno.land/x/xdg_portable@v10.6.0/src/platform-adapters/deno.deno.ts": "5f5852dc4588c10ad8fd0450421fa728741838cf5839a209d53323ccc9ed4c00", "https://esm.sh/jszip@3.7.1": "f3872a819b015715edb05f81d973b5cd05d3d213d8eb28293ca5471fe7a71773", "https://esm.sh/v135/jszip@3.7.1/denonext/jszip.mjs": "d31d7f9e0de9c6db3c07ca93f7301b756273d4dccb41b600461978fc313504c9" } diff --git a/deps/common.ts b/deps/common.ts index d81d085f..8843e4b4 100644 --- a/deps/common.ts +++ b/deps/common.ts @@ -10,7 +10,7 @@ export * as std_fmt_colors from "https://deno.land/std@0.213.0/fmt/colors.ts"; export * as std_url from "https://deno.land/std@0.213.0/url/mod.ts"; export * as std_path from "https://deno.land/std@0.213.0/path/mod.ts"; export * as std_fs from "https://deno.land/std@0.213.0/fs/mod.ts"; -export * as zod_val_err from "npm:zod-validation-error@3.3.0"; +export * as zod_val_err from "npm:zod-validation-error@3.4.0"; // avoid using the following directly and go through the // wrappers in ./utils/mod.ts diff --git a/deps/install.ts b/deps/install.ts new file mode 100644 index 00000000..ba2dc07f --- /dev/null +++ b/deps/install.ts @@ -0,0 +1 @@ +export { default as xdg } from "https://deno.land/x/xdg_portable@v10.6.0/src/mod.deno.ts"; diff --git a/docs/available-commands.md b/docs/available-commands.md deleted file mode 100644 index 79353a4d..00000000 --- a/docs/available-commands.md +++ /dev/null @@ -1,15 +0,0 @@ - - -| Command | Description | Subcommands/Flags | -|----------------|-------------|-------------------| -| ```ghjk sync``` | Synchronize your shell to what's in your config. | | -| ```ghjk envs ls``` | List environments defined in the ghjkfile. | | -| ```ghjk envs activate ``` | Activate an environment. | | -| ```ghjk ports resolve``` | Resolve all installs declared in config. | | -| ```ghjk ports outdated``` | Show a version table for installs. | `--update-all`: update all installs which their versions is not specified in the config.
`--update-only `: update a selected install | -| ```ghjk print``` | Emit different discovered and built values to stdout. | | -| ```ghjk deno``` | Access the deno cli. | | -| ```ghjk completions``` | Generate shell completions. | | - -You can use the following flag to get help around the CLI. -`ghjk --help` or `ghjk -h` diff --git a/docs/installation-vars.md b/docs/installation-vars.md new file mode 100644 index 00000000..967a944a --- /dev/null +++ b/docs/installation-vars.md @@ -0,0 +1,15 @@ +# Installer vars + +| Env vars | Desc | Default | +| -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | +| `GHJK_VERSION` | Git tag/ref of the ghjk repo to install from. | Latest release tag. | +| `GHJK_SHARE_DIR` | Root directory for ghjk installation. | `$HOME/.local/share/ghjk` | +| `GHJK_INSTALLER_URL` | Uri to the typescript section of installer script. | `install.ts` file from the ghjk repo under | +| `GHJK_INSTALL_EXE_DIR` | Location to install the `ghjk` exec. | `$HOME/.local/bin` | +| `GHJK_INSTALL_SKIP_EXE` | Weather or not to skip install the `ghjk` CLI to `GHJK_INSTALL_EXE_DIR`. | `false` | +| `GHJK_INSTALL_DENO_EXEC` | Alternative deno exec to use. If provided, no separate Deno CLI is downloaded. It's generally preferable for ghjk to manage it's own Deno versions still. | A Deno CLI is installed to `$GHJK_SHARE_DIR/bin` | +| `DENO_VERSION` | Deno version to install if `GHJK_INSTALL_DENO_EXEC` is not test. | Deno version used for ghjk development. | +| `GHJK_INSTALL_HOOK_SHELLS` | Comma separated list of shells to hook. | `bash,fish,zsh` | +| `GHJK_INSTALL_HOOK_MARKER` | Marker to use when installing shell hooks. | `ghjk-hook-marker` | +| | | | +| `GHJK_INSTALL_NO_LOCKFILE` | Disable use of a Deno lockfile for the ghjk program. | | diff --git a/docs/known-issues.md b/docs/known-issues.md new file mode 100644 index 00000000..22e06a63 --- /dev/null +++ b/docs/known-issues.md @@ -0,0 +1,28 @@ +# Known issues + +## GitHub API rate-limit + +The GitHub API is rate-limited to 60 calls per hour for unauthenticated requests. +Since many of the ports get their files from GitHub releases, it's easy to get past this limit especially in CI contexts. +This will manifest in failed 403 responses from ports trying to access the GitHub API. + +The best solution to this problem is to provide GitHub authentication tokens using the `GitHub_TOKEN` environment variable. +Authenticated requests have a rate-limit of 5000 calls per hour. +Most of the ports will make use of this in their API calls if this environment variable is detected. + +If you're using GitHub CI runners, this environment variable is [automatically](https://docs.GitHub.com/en/actions/security-for-GitHub-actions/security-guides/automatic-token-authentication) provided for you. +Otherwise, you'll need to generate [personal access tokens](https://docs.GitHub.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens) which can be used for this purpose. +More information on the GitHub rate limits can be found [here](https://docs.GitHub.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api?apiVersion=2022-11-28). + +## Leaking secure GitHub tokens + +Currently, any values captured by ports have to be persisted in the lockfile. +As most ports today make use of the `GitHub_TOKEN` environment variable, it's easy to leak these tokens into the ghjk lockfile which is intended to be committed. +Until a better solution can be devised for this, it's recommended to avoid using `GitHub_TOKEN`s on the development machine where commits are authored. +If the token ends up in your lockfile, be sure to clean it out before a commit is made. + +```bash +rm .ghjk/lock.json +# this command will re-resolve all ports +ghjk p resolve +``` diff --git a/docs/manual.md b/docs/manual.md new file mode 100644 index 00000000..f4dedf34 --- /dev/null +++ b/docs/manual.md @@ -0,0 +1,483 @@ +# User Manual + +Ghjk is a toolkit for declarative and programmatic configuration of POSIX runtime environments. +Currently in heavy development, it features working implementations of: +- Tool installation and management +- Task runner +- Declarative and dynamic environment variables + +This user manual is designed to be read on the Github web app within the repo that hosts the ghjk codebase. + + +## Installation + +Before anything, the ghjk CLI should be installed. +There are installer scripts available in the repo. + + +```bash +# stable +curl -fsSL https://raw.github.com/metatypedev/ghjk/v0.3.0-rc.1/install.sh | bash +``` + +This will install the CLI and add configuration your shell rc files the necessary hooks ghjk needs to function. +Installation can be customized through a number of environment variables that can be found [here](./installation-vars.md). + +## `ghjk.ts` + +Ghjk is configured through a ghjkfile. +Currently, a typescript based ghjkfile is available and the rest of this documents will use typescript for configuration. +Use the following command to create a starter file in the current directory: + +```bash +# initialize a `ghjk.ts` file +ghjk init ts +``` + +Look through the following snippet to understand the basic structure of a `ghjk.ts` file. + +```ts +// import the file function from `mod.ts` using the version of ghjk +// one's using. For example +// https://raw.github.com/metatypedev/ghjk/v0.3.0-rc.1/ +import { file } from ".../mod.ts"; +// import the port for the node program +import node from ".../ports/node.ts"; + +const ghjk = file(); + +// all ghjk.ts files are expected to export this special `sophon` object +// all the functions from the ghjk object are modifying the sophon +export const sophon = ghjk.sophon; + +// install programs (ports) into your env +ghjk.install( + node({ version: "14.17.0" }), +); + +// declare tasks to be available from the command line. +ghjk.task("greet", async ($) => { + await $`echo Hello ${$.argv}!`; +}); +``` + +One can look at the [examples](../examples/) found in the ghjk repo for an exploration of the different features available. + +## `$GHJK_DIR` + +Once you have a ghjkfile ready to go, the ghjk CLI can be used to access all the features your ghjkfile is using. +Augmenting the CLI are the hooks that were installed into your shells rc file (startup scripts like `~/.bashrc`). +These hooks check and modify your shell environment when you create a new one or `cd` (change directory) into a ghjk relevant directory. + +What constitutes a ghjk relevant directory? +- One that contains a recognized ghjkfile format like any file called `ghjk.ts` +- One that contains a `.ghjk` directory + +Note that if any parent directory contains these files, the current directory is considered part of that ghjk context. +The `$GHJKFILE` environment variable can be set to point the CLI and hooks at a different ghjkfile. + +The `.ghjk` dir is used by ghjk for different needs and contains some files you'll want to check into version control. +It includes its own `.gitignore` file by default that excludes all items not of interest for version control. +The `$GHJK_DIR` variable can be used to point the CLI at a different directory. + +## Serialized + +The ghjk CLI loads your typescript file in a worker to get at the actual configuration. +This process is called _serialization_. +The CLI generally operates on the output of this serialization though it might need to load your ghjkfile in a worker again, to execute task functions you've written for example. +While the details of the output are not important, this _serialize then do_ workflow defines how ghjk functions as we should see. + +The ghjk CLI serializes any discovered ghjkfile immediately when invoked. +In fact, what commands are available on the CLI are determined by the outputs of serialization. +If you declared tasks for example, ghjk will add the `tasks` sections to invoke them. + +To look at what the ghjkfile looks like serialized, you can use the following command: + +```bash +# look at the serialized form the ghjkfile +ghjk print config +``` + +#### The Hashfile + +Loading up typescript files in workers is not the quickest of operations as it turns out. +Ghjk caches output of this serialization to improve the latency of the CLI commands. +This raises the question how well the cache invalidation works in ghjk and that's a good question. +Cache invalidation is one of the hardest problems in computer science according to lore. + +Thankfully, through the great sandbox provided through Deno's implementation, the cache is invalidated when the following items change: +- The contents of the ghjkfile +- Files accessed during serialization +- Environment variables read during serialization + +This doesn't cover everything though and the `ghjk.ts` implementation generally assumes a declarative paradigm of programming. +You'll generally want to avoid any logic that's deterministic on inputs like time or RNGs. + +There are still a couple of glaring omissions from this list that will be addressed as ghjk matures. +If you encounter any edge cases or want to force re-serialization, you can remove the hashfile at `.ghjk/hash.json` which contains hashes for change tracking. + +```bash +# remove the hashfile to force re-serialization +$ rm .ghjk/hash.json +$ ghjk --help +``` + + + + +#### The Lockfile + +The cached value of the serialization results are stored in the lockfile. +The lockfile is what the different modules of ghjk use to store transient information that needs to be tracked across serializations. +Currently, this is mainly used by the port modules to retain version numbers resolved during installation which is important for the basic need of reproducibility. + +To maintain reproducibility across different machines, this file needs to be checked into version control. +Unfortunately, this can lead to version conflicts during git merges for example. + +One can always remove the `.ghjk/lock.json` to remove the lockfile and recreate it. +But this can not only lead to loss of information, it can take a long time since the ports module must query different package registries to resolve versions and more. + +The best way to resolve ghjk merge conflicts is to: +- Resolve the ghjkfile conflict in a traditional manner +- Instead of manually resolving the lockfile, just pick one version entirely + - In git, easier to remove any changes in the merge and revert to the base/HEAD branch +- Re-serialize by invoking the ghjk CLI + +This simple steps make sure that the _lockfile_ reflect what's in the latest _ghjkfile_ without needing to re-resolve the world. +Of course, if the discarded version of the lockfile contained new versions, they'll be re-resolved possibly to a different version. +But generally, if the versions specified in ghjkfile are tight enough, it'll resolve the same values as before. +If versions are important, it's good to explicitly specify them in your ghjkfile. + +The lockfile format itself is still in flux and there are plans to improve the merge conflict experience going forward. + +## Tasks + +Tasks are pretty simple to use. +You declare them in your ghjkfile, using typescript functions, and then invoke them from the the CLI. +The CLI will then load your ghjkfile in a worker and execute your function. + +```ts +import { file } from ".../mod.ts"; + +const ghjk = file(); + +ghjk.task("greet", async ($) => { + await $`echo Hello ${$.argv}!`; +}); +``` + +```bash +# list the available tasks +$ ghjk tasks + +# x is an alias for tasks +$ ghjk x + +# invoke the greet task +$ ghjk x greet ghjk +``` + +The `$` object is a enhanced version of the one from the [dax](https://jsr.io/david/jsr) library. +Amongst many things, it allows easy execution of shell commands in a cross platform way. +Look at the official documentation for all of it's illustrious powers. + +Tasks can also depend on each other meaning that the depended on task is always executed first. +Any arguments to the tasks are also passed on the `$` object or the second parameter object. +Look at the [tasks example](../examples/tasks/ghjk.ts) for more details.. + +## Envs + +Ghjk's environments, simply put, are a set of configurations for a POSIX environment. +POSIX environments are primarily defined by the current working directory and the set environment variables. +Ghjk envs then allow you: +- Set environment variables of course +- Add existing paths or newly installed program (ports) to the special `$PATH` variables +- Execute logic on entering and exiting envs +- Do all of this declaratively and in a composable manner + +Let's look at how one configures an environment using the `ghjk.ts` file: + +```ts +import { file } from ".../mod.ts"; + +const ghjk = file(); + +ghjk.env("my-env") + .var("MY_VAR", "hello POSIX!") + // we can return strings from typescript functions for dynamic + // variables + .var("MY_VAR_DYN", () => `Entered at ${new Date().toJSON()}`) + .onEnter(task(($) => console.log(`entering my-env`))) + .onExit(task(($) => console.log(`entering my-env`))) + ; +``` + +By default, your ghjkfile has an env called `main`. +Envs can inherit from each other and by default inherit from the `main` environment. +Inheritance is additive based for most env properties and allows easy composition. +Please look at the [envs example](../examples/envs/ghjk.ts) or the [kitchen sink](../examples/kitchen/ghjk.ts) example which show all the knobs available on envs. + +You can then access the envs feature under the `envs` section of the CLI: + +```bash +# look at avail sub commands +$ ghjk envs +# alias for envs +$ ghjk e +# list available envs +$ ghjk envs ls +``` + +Before we can _activate_ an environment, it needs to be _cooked_. +That is, entering an environment is a two step process. + +Cooking is what we call preparing the environment. +Required programs for the env are resolved and installed. +The shims for these programs are prepared. +The shell scripts to activate/deactivate it are prepared. +The results of env cooking are stored inside the `.ghjk/envs` directory. + +```bash +# cook a named env +$ ghjk e cook my-env +``` + +Once an environment is _cooked_, _activation_ is simple enough. +The name of the currently active environment is set to the `$GHJK_ENV` environment variable. + +```bash +# activate using the CLI +$ ghjk e activate my-env +$ echo $GHJK_ENV +# my-env +$ echo $MY_VAR +# hello POSIX! +``` + +When an env is activated in a shell session, the `ghjk_deactivate` command will be made available for deactivation. +This will remove the set variables and restore old ones if any were overwritten. +The ghjk shell hooks auto-deactivate any active environments from you shell, when it `cd`s away into a directory that's not part of the context. + +```bash +$ ghjk_deactivate +$ echo $MY_VAR +# +``` + +Note that the CLI activate command depends on the the ghjk shell hooks being available. +If not in an interactive shell, look at the CI section of this document for what options are available. + +#### `sync` + +The _cook_ and _activate_ process is common enough that there's a command available that does both, `sync`. +The `sync` command and both the `cook` and `activate` commands will operate on the currently active env if no env name argument is provided. +If no value is found at `$GHJK_ENV`, they'll use the set default env as described in the next section. + +```bash +# cook and activate an environment +$ ghjk sync my-env +``` + +### Default Env + +By default, the `main` environment is the one that's activated whenever you `cd` into the ghjk context. +You can change which env is activated by default using the `defaultEnv` setting. + +```bash +ghjk.config({ + defaultEnv: "my-env", +}); +``` + +`main` also serves as the default base all other envs inherit from. +The `defaultBaseEnv` parameter can be used to change this. + +```bash +ghjk.config({ + defaultBaseEnv: "main", +}); +``` + +## Ports + +Ports are small programs that ghjk executes to download and install programs. +When the env that includes a port installation is activated, a path to shims of the programs will be added to the special `$PATH` env variables. +This extends to modifying the appropriate `$PATH` variables for libraries or any environment variables needed for the program to function. +Currently, ports that are written in Deno flavoured typescript are supported and there's a small collection of such programs provided in the ghjk repository. + +The modules that implement port programs are also expected to expose a `conf` function as their default export. +The `conf` functions prove as a point of configuration for the port installation. +They return `InstallConfig` objects that describe user configuration along with where the port can be found and how to use it. +Any `InstallConfig` objects included in an env will then be resolved and installed when it's cooked. + +```ts +// the default export corresponds to the `conf` function +import node from ".../ports/node.ts"; +// the npmi installs executable packages from npm +import npmi from ".../ports/node.ts"; + +// top level `install` calls go to the `main` env +ghjk.install( + // configure installation for the node port + node({ version: "1.2.3" }), + // configure npmi to install the eslint package + npmi({ packageName: "eslint", version: "9" }) +); +``` + +We can then `sync` the main env to install and access the programs. + +```bash +# cook and activate +$ ghjk sync main +# the programs provided by the ports should now be available +$ node --version +$ eslint --version +``` + +### `buildDeps` + +While the Deno standard library and ESM url imports allow ports to do a lot, some ports require other programs to succeed at their tasks. +For example, the `npmi` port, which installs executable packages from npm, relies on the `npm` program for the actual functionality. +This is achieved by allowing ports to depend on other ports that they can use for tasks such as resolving available versions, downloading appropriate files, archive extraction, compilation...etc. + +As a soft security measure, ports are restricted to what other port they're allowed to depend on. +The default set includes common utilities like `curl`, `git`, `tar` and others which are used by most ports. +More ports can be easily added to the allowed port dep set. + +```ts +import { file } from ".../mod.ts"; +// barrel export for ports in the ghjk repo +import * as ports from "../../ports/mod.ts"; + +const ghjk = file(); + +ghjk.install( + ports.npmi({ packageName: "tsx" }) +) + +ghjk.config({ + allowedBuildDeps: [ + ports.node(), + ], +}); +``` + +The standard set of allowed port deps can be found [here](../modules/ports/std.ts). + +#### `enableRuntimes` + +The default set excludes scripting runtimes like `python` and `node` as another soft security measure. +Commonly used ports like `npmi`, `pipi` and `cargobi` rely on such ports to build and install programs from popular registries. +The `enableRuntimes` toggle can be used to add these common dependencies to the allowed build set. + +```ts +ghjk.config({ + enableRuntimes: true, +}); +``` + +One can look at the list of ports included by the flag [here](../modules/ports/std_runtime.ts) + +#### Ambient ports + +Ambient ports reuse programs already available on the system instead of downloading and installing one from the internet. +For a variety of reasons, the standard set of allowed port deps includes a number of these. +Please install the following programs first before attempting to use ghjk ports: + +- git +- tar (preferably GNU tar) +- curl +- unzip +- zstd + +### Writing ports + +The ports implementations is going through a lot of breaking changes. +If you need to author a new port right away, please look at the available implementations. + +## CI + +While the ghjk CLI and hooks are primarily designed for interactive shells in mind, they also support non-interactive use cases like scripts for CI jobs and for use in build tools. +The primarily difference between the two scenarios is how activation of envs is achieved as we shall see below. + +### Installation + +The standard installation script is the best way to install ghjk in CI environments. +The environment [variables](./installation-vars.md) used for the installer customization come in extra handy here. +Namely, it's good practice to: +- Make sure the `$GHJK_VERSION` is the one used by the ghjkfile. +- Specify `$GHJK_SHARE_DIR` to a location that can be cached by your CI tooling. This is where ports get installed. +- Specify `$GHJK_INSTALL_EXE_DIR` to a location that you know will be in `$PATH`. This is where the ghjk CLI gets installed to. + +```dockerfile +# sample of how one would install ghjk for use in a Dockerfile +ARG GHJK_VERSION=v0.3.0-rc.1 +# /usr/bin is available in $PATH by default making ghjk immediately avail +RUN curl -fsSL https://raw.github.com/metatypedev/ghjk/$GHJK_VERSION/install.sh \ + | GHJK_INSTALL_EXE_DIR=/usr/bin sh +``` + +### Activation + +When working on non-interactive shells, the ghjk shell hooks are not available. +This means that the default environment won't be activated for that CWD nor will any changes occur on changing directories. +It also prevents the `ghjk envs activate` command from functioning which requires that these hooks be run before each command. +In such scenarios, one can directly `source` the activation script for the target env from the `.ghjk` directory. + +```bash +# cooking must be done to make the activations scripts available +ghjk cook my-env +# there are scripts for POSIX and fish shells +# dot command is the preferred alias of source since it's the +# only one supported by POSIX sh +. .ghjk/envs/my-env/activate.sh +echo $GHJK_ENV +# my-env +echo $MY_VAR +# hello POSIX! +``` + +Make sure to activate the environment for every shell session in your CI scripts. +In a Dockerfile, which use POSIX sh, we'll need to: + +```dockerfile +# set GHJK_ENV for use +ENV GHJK_ENV=ci +ENV GHJK_ACTIVATE=.ghjk/envs/$GHJK_ENV/activate.sh +# cook $GHJK_ENV +RUN ghjk envs cook + +# each RUN command is a separate shell session +# and requires explicit activation +RUN . "$GHJK_ACTIVATE" \ + && echo $MY_VAR +``` + +This extra boilerplate can be avoided by using the SHELL command available in some Dockerfile implementations or by using command processors more advanced that POSIX sh. + +```dockerfile +# contraption to make sh load the activate script at startup +SHELL ["/bin/sh", "-c", ". .ghjk/envs/my-env/activate.sh; sh -c \"$*\"", "sh"] +RUN echo $MY_VAR +``` + +### Github action + +For users of Github CI, there's an action available on the [marketplace](https://github.com/marketplace/actions/ghjk-everything) that is able to: +- Installs ghjk CLI and hooks +- Caches the ghjk share directory +- Cooks the `$GHJK_ENV` or default environment + +Note that the default shell used by github workflows is POSIX `sh`. +It's necessary to switch over to the `bash` shell to have the hooks auto activate your environment. +Otherwise, it's necessary to use the approach described in the section above. + +```yaml + my-job: + steps: + - uses: metatypedev/setup-ghjk@v1 + - shell: bash # must use bash shell for auto activation + run: | + echo $GHJK_ENV +``` diff --git a/examples/env_vars/ghjk.ts b/examples/env_vars/ghjk.ts index e670d440..1d98f92c 100644 --- a/examples/env_vars/ghjk.ts +++ b/examples/env_vars/ghjk.ts @@ -16,6 +16,6 @@ const { env, task } = ghjk; env("main") .var("A", "A#STATIC") - .var("C", ($) => $`echo C [$A, $B]`.text()) .var("B", () => "B#DYNAMIC") + .var("C", ($) => $`echo C [$A, $B]`.text()) .onEnter(task(($) => $`echo enter $A, $B, $C`)); diff --git a/examples/kitchen/ghjk.ts b/examples/kitchen/ghjk.ts index a88897e4..ca2aa829 100644 --- a/examples/kitchen/ghjk.ts +++ b/examples/kitchen/ghjk.ts @@ -119,4 +119,5 @@ env("dev") .onEnter(task({ workingDir: "..", fn: ($) => $`ls`, - })); + })) + .onExit(task(($) => $`echo exit`)); diff --git a/files/deno/bindings.ts b/files/deno/bindings.ts new file mode 100644 index 00000000..8bf47f10 --- /dev/null +++ b/files/deno/bindings.ts @@ -0,0 +1,35 @@ +//! this loads the ghjk.ts module and provides a program for it + +//// +/// + +// all imports in here should be dynamic imports as we want to +// modify the Deno namespace before anyone touches it + +// NOTE: only import types +import { shimDenoNamespace } from "../../utils/worker.ts"; +import { zod } from "../../deps/common.ts"; +import { Ghjk } from "../../src/ghjk/js/runtime.js"; + +const serializeArgs = zod.object({ + uri: zod.string(), +}); + +async function serialize(args: zod.infer) { + const shimHandle = shimDenoNamespace(Deno.env.toObject()); + const { setup: setupLogger } = await import("../../utils/logger.ts"); + setupLogger(); + const mod = await import(args.uri); + const rawConfig = await mod.sophon.getConfig(args.uri, mod.secureConfig); + const config = JSON.parse(JSON.stringify(rawConfig)); + return { + config, + accessedEnvKeys: shimHandle.getAccessedEnvKeys(), + readFilePaths: shimHandle.getReadFiles(), + listedFilePaths: shimHandle.getListedFiles(), + }; +} + +const args = serializeArgs.parse(Ghjk.blackboard.get("args")); +const resp = await serialize(args); +Ghjk.blackboard.set("resp", resp); diff --git a/files/deno/mod.ts b/files/deno/mod.ts index 4b566ceb..9eca6e14 100644 --- a/files/deno/mod.ts +++ b/files/deno/mod.ts @@ -53,6 +53,7 @@ async function rpc(moduleUri: string, req: DriverRequests) { write: false, run: false, ffi: false, + import: true, } as Deno.PermissionOptions, }, } as WorkerOptions); diff --git a/files/deno/worker.ts b/files/deno/worker.ts index 5a9528f7..ca55221d 100644 --- a/files/deno/worker.ts +++ b/files/deno/worker.ts @@ -6,8 +6,8 @@ // all imports in here should be dynamic imports as we want to // modify the Deno namespace before anyone touches it -// NOTE: only import types import { shimDenoNamespace } from "../../utils/worker.ts"; +// NOTE: only import types import type { DriverRequests, DriverResponse } from "./mod.ts"; self.onmessage = onMsg; diff --git a/files/mod.ts b/files/mod.ts index 44c03228..dc30b666 100644 --- a/files/mod.ts +++ b/files/mod.ts @@ -25,8 +25,7 @@ import { unwrapZodRes, } from "../utils/mod.ts"; import * as std_ports from "../modules/ports/std.ts"; -import * as cpy from "../ports/cpy_bs.ts"; -import * as node from "../ports/node.ts"; +import runtime_ports from "../modules/ports/std_runtime.ts"; // host import type { SerializedConfig } from "../host/types.ts"; import * as std_modules from "../modules/std.ts"; @@ -1085,15 +1084,14 @@ export function stdDeps(args = { enableRuntimes: false }) { if (args.enableRuntimes) { out.push( ...reduceAllowedDeps([ - node.default(), - cpy.default(), + ...runtime_ports, ]), ); } return out; } -function task$( +export function task$( argv: string[], env: Record, workingDir: string, diff --git a/ghjk.ts b/ghjk.ts index 3560a6ab..79e8be0c 100644 --- a/ghjk.ts +++ b/ghjk.ts @@ -1,43 +1,173 @@ +// @ts-nocheck: Ghjkfile based on Deno + export { sophon } from "./hack.ts"; -import { config, install, task } from "./hack.ts"; +import { config, env, install, task } from "./hack.ts"; +import { switchMap } from "./port.ts"; import * as ports from "./ports/mod.ts"; import { sedLock } from "./std.ts"; +import { downloadFile, DownloadFileArgs } from "./utils/mod.ts"; +import { unarchive } from "./utils/unarchive.ts"; +import dummy from "./ports/dummy.ts"; + +// keep in sync with the deno repo's ./rust-toolchain.toml +const RUST_VERSION = "1.82.0"; + +const installs = { + rust: ports.rust({ + version: RUST_VERSION, + profile: "default", + components: ["rust-src"], + }), +}; config({ - defaultBaseEnv: "test", + defaultEnv: "dev", enableRuntimes: true, + allowedBuildDeps: [ports.cpy_bs({ version: "3.13.1" }), installs.rust], +}); + +env("main").vars({ + RUST_LOG: [ + "info", + Object.entries({ + "TRACE": [ + // "denort", + // "deno", + ], + "DEBUG": [ + // "runtime", + // "tokio", + ], + "INFO": [ + "deno::npm", + "deno::file_fetcher", + "swc_ecma_transforms_base", + "swc_common", + "h2", + "rustls", + "mio", + "hyper_util", + ], + }).flatMap(([level, modules]) => + modules.map((module) => `${module}=${level.toLowerCase()}`) + ), + ].join(), }); +env("_rust") + .install( + ports.protoc(), + ports.pipi({ packageName: "cmake" })[0], + installs.rust, + ); + +const RUSTY_V8_MIRROR = `${import.meta.dirname}/.dev/rusty_v8`; + +env("dev") + .inherit("_rust") + .install(ports.cargobi({ crateName: "tokio-console" })) + .vars({ + // V8_FORCE_DEBUG: "true", + RUSTY_V8_MIRROR, + }); + +if (Deno.build.os == "linux" && !Deno.env.has("NO_MOLD")) { + const mold = ports.mold({ + version: "v2.4.0", + replaceLd: true, + }); + env("dev").install(mold); +} + // these are just for quick testing -install(); +install( + ports.asdf({ + pluginRepo: "https://github.com/lsanwick/asdf-jq", + installType: "version", + }), +); -const DENO_VERSION = "1.44.2"; +const DENO_VERSION = "2.1.2"; // these are used for developing ghjk install( ports.act(), ports.pipi({ packageName: "pre-commit" })[0], - ports.cpy_bs(), + ports.pipi({ packageName: "vale" })[0], ports.deno_ghrel({ version: DENO_VERSION }), ); +task( + "cache-v8", + { + desc: "Install the V8 builds to a local cache.", + inherit: false, + fn: async ($) => { + const tmpDirPath = await Deno.makeTempDir({}); + const v8Versions = [ + ...(await $`cargo tree -p v8 --depth 0 --locked` + .text()) + .matchAll(/^v8 (v[\d.]*)/g) + .map((match) => match[1]), + ]; + + await $.co( + v8Versions + .flatMap( + (version) => { + const os = switchMap(Deno.build.os, { + linux: "unknown-linux-gnu", + darwin: "apple-darwin", + }) ?? "NOT_SUPPORTED"; + const arch = Deno.build.arch; + return [ + `librusty_v8_release_${arch}-${os}.a.gz`, + `librusty_v8_debug_${arch}-${os}.a.gz`, + ].map((archiveName) => ({ + archiveName, + url: + `https://github.com/denoland/rusty_v8/releases/download/${version}/${archiveName}`, + downloadPath: $.path(RUSTY_V8_MIRROR).join(version).toString(), + tmpDirPath, + } satisfies DownloadFileArgs)); + }, + ) + .filter((args) => + !$.path(args.downloadPath).join(args.archiveName).existsSync() + ) + .map((args) => downloadFile(args)), + ); + await $.path(tmpDirPath).remove({ recursive: true }); + }, + }, +); + task( "lock-sed", async ($) => { - const GHJK_VERSION = "0.2.1"; + const GHJK_VERSION = "0.3.0-rc.1"; await sedLock( $.path(import.meta.dirname!), { lines: { + "./rust-toolchain.toml": [ + [/^(channel = ").*(")/, RUST_VERSION], + ], + "./Cargo.toml": [ + [/^(version = ").*(")/, GHJK_VERSION], + ], "./.github/workflows/*.yml": [ [/(DENO_VERSION: ").*(")/, DENO_VERSION], ], - "./host/mod.ts": [ - [/(GHJK_VERSION = ").*(")/, GHJK_VERSION], - ], - "./install.sh": [ - [/(GHJK_VERSION="\$\{GHJK_VERSION:-v).*(\}")/, GHJK_VERSION], - [/(DENO_VERSION="\$\{DENO_VERSION:-v).*(\}")/, DENO_VERSION], + "./docs/*.md": [ + [ + /(.*\/metatypedev\/ghjk\/v)[^/]*(\/.*)/, + GHJK_VERSION, + ], + [ + /(GHJK_VERSION\s*=\s*v)[^\s]*(.*)/, + GHJK_VERSION, + ], ], "./README.md": [ [ @@ -45,6 +175,13 @@ task( GHJK_VERSION, ], ], + "**/Cargo.toml": [ + [/^(version = ").+(")/, GHJK_VERSION], + [ + /(deno\s*=\s*\{\s*git\s*=\s*"https:\/\/github\.com\/metatypedev\/deno"\s*,\s*branch\s*=\s*"v).+(-embeddable"\s*\})/, + DENO_VERSION, + ], + ], }, ignores: [ // ignore this file to avoid hits on the regexps @@ -65,4 +202,5 @@ task( }, ); }, + { inherits: false }, ); diff --git a/hack.ts b/hack.ts index bb093358..3d2ebeb8 100644 --- a/hack.ts +++ b/hack.ts @@ -15,6 +15,7 @@ export const config = Object.freeze(firstCallerCheck(ghjk.config)); export const env = Object.freeze(firstCallerCheck(ghjk.env)); export const install = Object.freeze(firstCallerCheck(ghjk.install)); export const task = Object.freeze(firstCallerCheck(ghjk.task)); +export const tasks = Object.freeze(firstCallerCheck(ghjk.tasks)); // capture exit fn to avoid malicous caller from // changing it on Deno object diff --git a/host/init/mod.ts b/host/init/mod.ts new file mode 100644 index 00000000..510c20a1 --- /dev/null +++ b/host/init/mod.ts @@ -0,0 +1,185 @@ +import { DenoTaskDefArgs, task$ } from "../../files/mod.ts"; +import { zod } from "../../deps/common.ts"; +import { + findEntryRecursive, + importRaw, + Path, + unwrapZodRes, +} from "../../utils/mod.ts"; + +// NOTE: only limited subset of task featutres are avail. +// no environments and deps +const tasks: Record = { + "init-ts": { + desc: "Create a typescript ghjkfile in the current directory.", + async fn($, args) { + { + const ghjkdir = $.env["GHJK_DIR"] ?? + await findEntryRecursive($.workingDir, ".ghjk"); + if (ghjkdir) { + throw new Error( + `already in a ghjkdir context located at: ${ghjkdir}`, + ); + } + } + const ghjkFilePath = $.workingDir.join("ghjk.ts"); + if (!await ghjkFilePath.exists()) { + const templatePath = import.meta.resolve("./template.ts"); + const ghjkRoot = import.meta.resolve("../../"); + const template = await importRaw(templatePath); + const final = template.replaceAll( + /from "..\/..\/(.*)"; \/\/ template-import/g, + `from "${ghjkRoot}$1";`, + ); + await ghjkFilePath.writeText(final); + $.logger.info("written ghjk.ts to", ghjkFilePath); + await tasks["init-ts-lsp"].fn!($, args); + } + }, + }, + "init-ts-lsp": { + desc: + "Interactively configure working directory for best LSP support of ghjk.ts. Pass --yes to confirm every choice.", + async fn($) { + const all = $.argv[0] == "--yes"; + const ghjkfile = $.env["GHJKFILE"] ?? "ghjk.ts"; + const changeVscodeSettings = all || await $.confirm( + `Configure deno lsp to selectively enable on ${ghjkfile} through .vscode/settings.json?`, + { + default: true, + }, + ); + if (changeVscodeSettings) { + const vscodeSettingsRaw = await $.prompt( + "Path to .vscode/settings.json ghjk working dir", + { + default: ".vscode/settings.json", + }, + ); + await handleVscodeSettings( + $, + ghjkfile, + $.workingDir.join(vscodeSettingsRaw), + ); + } + const ghjkfilePath = $.workingDir.join(ghjkfile); + if (await ghjkfilePath.exists()) { + const content = await ghjkfilePath.readText(); + if (/@ts-nocheck/.test(content)) { + $.logger.info(`@ts-nocheck detected in ${ghjkfile}, skipping`); + return; + } + const changeGhjkts = await $.confirm( + `Mark ${ghjkfile} with @ts-nocheck`, + { + default: true, + }, + ); + if (changeGhjkts) { + await ghjkfilePath.writeText(` +// @ts-nocheck: Ghjkfile based on Deno + +${content}`); + } + } + }, + }, +}; + +async function handleVscodeSettings( + $: ReturnType, + ghjkfile: string, + vscodeSettings: Path, +) { + if (!await vscodeSettings.exists()) { + $.logger.error( + `No file detected at ${vscodeSettings}, creating a new one.`, + ); + const config = { + "deno.enablePaths": [ + ghjkfile, + ], + }; + vscodeSettings.writeJsonPretty(config); + $.logger.info(`Wrote config to ${vscodeSettings}`, config); + return; + } + + const schema = zod.object({ + "deno.enablePaths": zod.string().array().optional(), + "deno.disablePaths": zod.string().array().optional(), + deno: zod.object({ + enablePaths: zod.string().array().optional(), + disablePaths: zod.string().array().optional(), + }).passthrough().optional(), + }).passthrough(); + + const originalConfig = await vscodeSettings.readJson() + .catch((err) => { + throw new Error(`error parsing JSON at ${vscodeSettings}`, { + cause: err, + }); + }); + const parsedConfig = unwrapZodRes(schema.safeParse(originalConfig), { + originalConfig, + }, "unexpected JSON discovored at .vscode/settings.json"); + + let writeOut = false; + + if (parsedConfig["deno.enablePaths"]) { + if (!parsedConfig["deno.enablePaths"].includes(ghjkfile)) { + $.logger.info( + `Adding ${ghjkfile} to "deno.enablePaths"`, + ); + parsedConfig["deno.enablePaths"].push(ghjkfile); + writeOut = true; + } else { + $.logger.info( + `Detected ${ghjkfile} in "deno.enablePaths", skipping`, + ); + } + } else if (parsedConfig.deno?.enablePaths) { + if (!parsedConfig.deno.enablePaths.includes(ghjkfile)) { + $.logger.info( + `Adding ${ghjkfile} to deno.enablePaths`, + ); + parsedConfig.deno.enablePaths.push(ghjkfile); + writeOut = true; + } else { + $.logger.info( + `Detected ${ghjkfile} in deno.enablePaths, skipping`, + ); + } + } else if (parsedConfig["deno.disablePaths"]) { + if (parsedConfig["deno.disablePaths"].includes(ghjkfile)) { + throw new Error( + `${ghjkfile} detected in "deno.disablePaths". Confused :/`, + ); + } else { + $.logger.info( + `No ${ghjkfile} in "deno.disablePaths", skipping`, + ); + } + } else if (parsedConfig.deno?.disablePaths) { + if (parsedConfig.deno.disablePaths.includes(ghjkfile)) { + throw new Error( + `${ghjkfile} detected in deno.disablePaths. Confused :/`, + ); + } else { + $.logger.info( + `No ${ghjkfile} in deno.disablePaths, skipping`, + ); + } + } else { + parsedConfig["deno.enablePaths"] = [ghjkfile]; + writeOut = true; + $.logger.info( + `Adding ${ghjkfile} to "deno.enablePaths"`, + ); + } + if (writeOut) { + vscodeSettings.writeJsonPretty(parsedConfig); + $.logger.info(`Wrote config to ${vscodeSettings}`, parsedConfig); + } +} +export default tasks; diff --git a/host/init/template.ts b/host/init/template.ts new file mode 100644 index 00000000..fdf1460e --- /dev/null +++ b/host/init/template.ts @@ -0,0 +1,22 @@ +// @ts-nocheck: Deno based + +import { file } from "../../mod.ts"; // template-import +// import * as ports from "../../ports/mod.ts"; // template-import + +const ghjk = file({ + // allows usage of ports that depend on node/python + // enableRuntimes: true, +}); + +// This export is necessary for ts ghjkfiles +export const sophon = ghjk.sophon; + +ghjk.install( + // install ports into the main env + // ports.node(), + // ports.cpy_bs(), +); + +ghjk.task("greet", async ($) => { + await $`echo Hello ${$.argv}`; +}); diff --git a/host/mod.ts b/host/mod.ts deleted file mode 100644 index 8a62b233..00000000 --- a/host/mod.ts +++ /dev/null @@ -1,597 +0,0 @@ -import { cliffy_cmd, deep_eql, zod, zod_val_err } from "../deps/cli.ts"; -import logger from "../utils/logger.ts"; -import { - $, - bufferHashAsync, - Json, - objectHash, - Path, - stringHash, -} from "../utils/mod.ts"; -import validators, { SerializedConfig } from "./types.ts"; -import * as std_modules from "../modules/std.ts"; -import * as denoFile from "../files/deno/mod.ts"; -import type { ModuleBase } from "../modules/mod.ts"; -import { GhjkCtx } from "../modules/types.ts"; -import { serializePlatform } from "../modules/ports/types/platform.ts"; - -export interface CliArgs { - ghjkShareDir: string; - ghjkfilePath?: string; - ghjkDirPath?: string; - reFlagSet: boolean; - lockedFlagSet: boolean; -} - -type HostCtx = { - fileHashMemoStore: Map>; - curEnvVars: Record; - reFlagSet: boolean; - lockedFlagSet: boolean; -}; - -const GHJK_VERSION = "0.2.1"; - -export async function cli(args: CliArgs) { - logger().debug(`ghjk CLI`, GHJK_VERSION); - if (args.reFlagSet && args.lockedFlagSet) { - throw new Error("GHJK_LOCKED && GHJK_RE both set"); - } - // items to run at end of function - const defer = [] as (() => Promise)[]; - - const ghjkShareDir = $.path(args.ghjkShareDir).resolve().normalize(); - let serializedConfig: object | undefined; - let gcx: GhjkCtx | undefined; - - if (!args.ghjkDirPath && args.ghjkfilePath) { - args.ghjkDirPath = $.path(args.ghjkfilePath).parentOrThrow().join(".ghjk") - .toString(); - } - - const subcmds: Record = {}; - - // most of the CLI is only avail if there's a - // ghjkfile detected - if (args.ghjkDirPath) { - gcx = { - ghjkShareDir, - ghjkDir: $.path(args.ghjkDirPath).resolve().normalize(), - ghjkfilePath: args.ghjkfilePath - ? $.path(args.ghjkfilePath).resolve().normalize() - : undefined, - blackboard: new Map(), - }; - const hcx: HostCtx = { - fileHashMemoStore: new Map(), - curEnvVars: Deno.env.toObject(), - reFlagSet: args.reFlagSet, - lockedFlagSet: args.lockedFlagSet, - }; - logger().debug("context established", { - ghjkDir: gcx?.ghjkDir.toString(), - ghjkfilePath: gcx.ghjkfilePath?.toString(), - }); - - if (!await gcx.ghjkDir.join(".gitignore").exists()) { - gcx.ghjkDir.join(".gitignore").writeText($.dedent` - envs - hash.json`); - } - - // this returns nothing if no valid lockifle or ghjkfile - // is found - const commands = await commandsFromConfig(hcx, gcx); - if (commands) { - serializedConfig = commands.config; - // lock entries are also generated across program usage - // so we defer another write out until the end - defer.push(commands.writeLockFile); - - for ( - const [cmdName, [cmd, src]] of Object.entries(commands.subCommands) - ) { - const conflict = subcmds[cmdName]; - if (conflict) { - throw new Error( - `CLI command conflict under name "${cmdName}" from host and module "${src}"`, - ); - } - subcmds[cmdName] = cmd; - } - } - } - - const root = new cliffy_cmd.Command() - .name("ghjk") - .version(GHJK_VERSION) - .description("Programmable runtime manager.") - .action(function () { - this.showHelp(); - }) - .command( - "completions", - new cliffy_cmd.CompletionsCommand(), - ) - .command( - "deno", - new cliffy_cmd.Command() - .description("Access the deno cli.") - .useRawArgs() - .action(async function (_, ...args) { - logger().debug(args); - await $.raw`${Deno.execPath()} ${args}` - .env("DENO_EXEC_PATH", Deno.execPath()); - }), - ) - .command( - "print", - new cliffy_cmd.Command() - .description("Emit different discovered and built values to stdout.") - .action(function () { - this.showHelp(); - }) - .command( - "share-dir-path", - new cliffy_cmd.Command() - .description("Print the path where ghjk is installed in.") - .action(function () { - if (!ghjkShareDir) { - throw new Error("no ghjkfile found."); - } - // deno-lint-ignore no-console - console.log(ghjkShareDir.toString()); - }), - ) - .command( - "ghjkdir-path", - new cliffy_cmd.Command() - .description("Print the path where ghjk is installed in.") - .action(function () { - if (!gcx) { - throw new Error("no ghjkfile found."); - } - // deno-lint-ignore no-console - console.log(gcx.ghjkDir.toString()); - }), - ) - .command( - "ghjkfile-path", - new cliffy_cmd.Command() - .description("Print the path of the ghjk.ts used") - .action(function () { - if (!gcx?.ghjkfilePath) { - throw new Error("no ghjkfile found."); - } - // deno-lint-ignore no-console - console.log(gcx.ghjkfilePath.toString()); - }), - ) - .command( - "config", - new cliffy_cmd.Command() - .description( - "Print the extracted ans serialized config from the ghjkfile", - ) - .option( - "--json", - `Use json format when printing config.`, - ) - .action(function ({ json }) { - if (!serializedConfig) { - throw new Error("no ghjkfile found."); - } - // deno-lint-ignore no-console - console.log( - json - ? JSON.stringify(serializedConfig) - : $.inspect(serializedConfig), - ); - }), - ), - ); - for (const [name, subcmd] of Object.entries(subcmds)) { - root.command(name, subcmd); - } - try { - await root.parse(Deno.args); - } catch (err) { - logger().error(err); - Deno.exit(1); - } finally { - await Promise.all(defer.map((fn) => fn())); - } -} - -async function commandsFromConfig(hcx: HostCtx, gcx: GhjkCtx) { - const lockFilePath = gcx.ghjkDir.join("lock.json"); - const hashFilePath = gcx.ghjkDir.join("hash.json"); - - const foundLockObj = await readLockFile(lockFilePath); - const foundHashObj = await readHashFile(hashFilePath); - - if (hcx.lockedFlagSet) { - if (!foundLockObj) { - throw new Error("GHJK_LOCKED set but no lockfile found"); - } - if (!foundHashObj) { - throw new Error("GHJK_LOCKED set but no hashfile found"); - } - } - - const lockEntries = {} as Record; - - const ghjkfileHash = await gcx.ghjkfilePath?.exists() - ? await fileDigestHex(hcx, gcx.ghjkfilePath!) - : undefined; - - if (!hcx.reFlagSet && foundLockObj) { - logger().debug("loading lockfile", lockFilePath); - for (const man of foundLockObj.config.modules) { - const mod = std_modules.map[man.id]; - if (!mod) { - throw new Error( - `unrecognized module specified by lockfile config: ${man.id}`, - ); - } - const entry = foundLockObj.moduleEntries[man.id]; - if (!entry) { - throw new Error( - `no lock entry found for module specified by lockfile config: ${man.id}`, - ); - } - const instance: ModuleBase = new mod.ctor(); - lockEntries[man.id] = await instance.loadLockEntry( - gcx, - entry as Json, - ); - } - } - - let configExt: SerializedConfigExt | null = null; - let wasReSerialized = false; - if ( - !hcx.reFlagSet && - foundLockObj && - foundHashObj && - (hcx.lockedFlagSet || - // avoid reserializing the config if - // the ghjkfile and environment is _satisfcatorily_ - // similar. "cache validation" - foundLockObj.version == "0" && - await isHashFileValid(hcx, foundLockObj, foundHashObj, ghjkfileHash)) - ) { - configExt = { - config: foundLockObj.config, - envVarHashes: foundHashObj.envVarHashes, - readFileHashes: foundHashObj.readFileHashes, - listedFiles: foundHashObj.listedFiles, - }; - } else if (gcx.ghjkfilePath) { - logger().info("serializing ghjkfile", gcx.ghjkfilePath); - configExt = await readGhjkfile(hcx, gcx.ghjkfilePath); - wasReSerialized = true; - } else { - // nothing to get the commands from - return; - } - - const newHashObj: zod.infer = { - version: "0", - ghjkfileHash, - envVarHashes: configExt.envVarHashes, - readFileHashes: configExt.readFileHashes, - listedFiles: configExt.listedFiles, - }; - // command name to [cmd, source module id] - const subCommands = {} as Record; - const instances = [] as [string, ModuleBase, unknown][]; - - for (const man of configExt.config.modules) { - const mod = std_modules.map[man.id]; - if (!mod) { - throw new Error(`unrecognized module specified by ghjk.ts: ${man.id}`); - } - const instance: ModuleBase = new mod.ctor(); - const pMan = await instance.processManifest( - gcx, - man, - configExt.config.blackboard, - lockEntries[man.id], - ); - instances.push([man.id, instance, pMan] as const); - for (const [cmdName, cmd] of Object.entries(instance.commands(gcx, pMan))) { - const conflict = subCommands[cmdName]; - if (conflict) { - throw new Error( - `CLI command conflict under name "${cmdName}" from modules "${man.id}" & "${ - conflict[1] - }"`, - ); - } - subCommands[cmdName] = [cmd, man.id]; - } - } - - if ( - !hcx.lockedFlagSet && wasReSerialized && ( - !foundHashObj || !deep_eql(newHashObj, foundHashObj) - ) - ) { - await hashFilePath.writeJsonPretty(newHashObj); - } - - // `writeLockFile` can be invoked multiple times - // so we keep track of the last lockfile wrote - // out to disk - // TODO(#90): file system lock file while ghjk is running - // to avoid multiple instances from clobbering each other - let lastLockObj = { ...foundLockObj }; - return { - subCommands, - config: configExt.config, - async writeLockFile() { - if (hcx.lockedFlagSet) return; - - const newLockObj: zod.infer = { - version: "0", - platform: serializePlatform(Deno.build), - moduleEntries: {} as Record, - config: configExt!.config, - }; - - // generate the lock entries after *all* the modules - // are done processing their config to allow - // any shared stores to be properly populated - // e.g. the resolution memo store - newLockObj.moduleEntries = Object.fromEntries( - await Array.fromAsync( - instances.map( - async ( - [id, instance, pMan], - ) => [id, await instance.genLockEntry(gcx, pMan)], - ), - ), - ); - // avoid writing lockfile if nothing's changed - if (!lastLockObj || !deep_eql(newLockObj, lastLockObj)) { - lastLockObj = { ...newLockObj }; - await lockFilePath.writeJsonPretty(newLockObj); - } - }, - }; -} - -async function isHashFileValid( - hcx: HostCtx, - foundLockFile: zod.infer, - foundHashFile: zod.infer, - ghjkfileHash?: string, -) { - // TODO: figure out cross platform lockfiles :O - const platformMatch = () => - serializePlatform(Deno.build) == foundLockFile.platform; - - const envHashesMatch = () => { - const oldHashes = foundHashFile!.envVarHashes; - const newHashes = envVarDigests(hcx.curEnvVars, [ - ...Object.keys(oldHashes), - ]); - return deep_eql(oldHashes, newHashes); - }; - - const cwd = $.path(Deno.cwd()); - const fileHashesMatch = async () => { - const oldHashes = foundHashFile!.readFileHashes; - const newHashes = await fileDigests(hcx, [ - ...Object.keys(oldHashes), - ], cwd); - return deep_eql(oldHashes, newHashes); - }; - - const fileListingsMatch = async () => { - const oldListed = foundHashFile!.listedFiles; - for (const path of oldListed) { - if (!await cwd.resolve(path).exists()) { - return false; - } - } - return true; - }; - // NOTE: these are ordered by the amount effort it takes - // to check each - // we only check file hash of the ghjk file if it's present - return (ghjkfileHash ? foundHashFile.ghjkfileHash == ghjkfileHash : true) && - platformMatch() && - envHashesMatch() && - await fileListingsMatch() && - await fileHashesMatch(); -} - -type DigestsMap = Record; - -type SerializedConfigExt = Awaited< - ReturnType ->; - -async function readGhjkfile( - hcx: HostCtx, - configPath: Path, -) { - switch (configPath.extname()) { - case "": - logger().warn("config file has no extension, assuming deno config"); - /* falls through */ - case ".ts": { - logger().debug("serializing ts config", configPath); - const res = await denoFile.getSerializedConfig( - configPath.toFileUrl().href, - hcx.curEnvVars, - ); - const envVarHashes = envVarDigests(hcx.curEnvVars, res.accessedEnvKeys); - const cwd = $.path(Deno.cwd()); - const cwdStr = cwd.toString(); - const listedFiles = res.listedFiles - .map((path) => cwd.resolve(path).toString().replace(cwdStr, ".")); - // FIXME: this breaks if the version of the file the config reads - // has changed by this point - // consider reading mtime of files when read by the serializer and comparing - // them before hashing to make sure we get the same file - // not sure what to do if it has changed though, re-serialize? - const readFileHashes = await fileDigests(hcx, res.readFiles, cwd); - - return { - config: validateRawConfig(res.config, configPath), - envVarHashes, - readFileHashes, - listedFiles, - }; - } - // case ".jsonc": - // case ".json": - // raw = await configPath.readJson(); - // break; - default: - throw new Error( - `unrecognized ghjkfile type provided at path: ${configPath}`, - ); - } -} - -function validateRawConfig( - raw: unknown, - configPath: Path, -): SerializedConfig { - try { - return validators.serializedConfig.parse(raw); - } catch (err) { - const validationError = zod_val_err.fromError(err); - throw new Error( - `error parsing seralized config from ${configPath}: ${validationError.toString()}`, - { - cause: validationError, - }, - ); - } -} - -const lockObjValidator = zod.object({ - version: zod.string(), - platform: zod.string(), // TODO custom validator?? - moduleEntries: zod.record(zod.string(), zod.unknown()), - config: validators.serializedConfig, -}); - -/** - * The lock.json file stores the serialized config and some entries - * from modules. It's primary purpose is as a memo store to avoid - * re-serialization on each CLI invocation. - */ -async function readLockFile(lockFilePath: Path) { - const rawStr = await lockFilePath.readMaybeText(); - if (!rawStr) return; - try { - const rawJson = JSON.parse(rawStr); - return lockObjValidator.parse(rawJson); - } catch (err) { - const validationError = zod_val_err.fromError(err); - logger().error( - `error parsing lockfile from ${lockFilePath}: ${validationError.toString()}`, - ); - if (Deno.stderr.isTerminal() && await $.confirm("Discard lockfile?")) { - return; - } else { - throw validationError; - } - } -} - -const hashObjValidator = zod.object({ - version: zod.string(), - ghjkfileHash: zod.string().nullish(), - envVarHashes: zod.record(zod.string(), zod.string().nullish()), - readFileHashes: zod.record(zod.string(), zod.string().nullish()), - listedFiles: zod.string().array(), - // TODO: track listed dirs in case a `walk`ed directory has a new entry -}); - -/** - * The hash.json file stores the digests of all external accesses - * of a ghjkfile during serialization. The primary purpose is to - * do "cache invalidation" on ghjkfiles, re-serializing them if - * any of the digests change. - */ -async function readHashFile(hashFilePath: Path) { - const rawStr = await hashFilePath.readMaybeText(); - if (!rawStr) return; - try { - const rawJson = JSON.parse(rawStr); - return hashObjValidator.parse(rawJson); - } catch (err) { - logger().error( - `error parsing hashfile from ${hashObjValidator}: ${ - zod_val_err.fromError(err).toString() - }`, - ); - logger().warn("discarding invalid hashfile"); - return; - } -} - -function envVarDigests(all: Record, accessed: string[]) { - const hashes = {} as DigestsMap; - for (const key of accessed) { - const val = all[key]; - if (!val) { - // use null if the serializer accessed - hashes[key] = null; - } else { - hashes[key] = stringHash(val); - } - } - return hashes; -} - -async function fileDigests(hcx: HostCtx, readFiles: string[], cwd: Path) { - const cwdStr = cwd.toString(); - const readFileHashes = {} as DigestsMap; - await Promise.all(readFiles.map(async (pathStr) => { - const path = cwd.resolve(pathStr); - const relativePath = path - .toString() - .replace(cwdStr, "."); - // FIXME: stream read into hash to improve mem usage - const stat = await path.lstat(); - if (stat) { - const contentHash = (stat.isFile || stat.isSymlink) - ? await fileDigestHex(hcx, path) - : null; - readFileHashes[relativePath] = objectHash({ - ...JSON.parse(JSON.stringify(stat)), - contentHash, - }); - } else { - readFileHashes[relativePath] = null; - } - })); - return readFileHashes; -} - -/** - * Returns the hash digest of a file. Makes use of a memo - * to dedupe work. - */ -function fileDigestHex(hcx: HostCtx, path: Path) { - const absolute = path.resolve().toString(); - let promise = hcx.fileHashMemoStore.get(absolute); - if (!promise) { - promise = inner(); - hcx.fileHashMemoStore.set(absolute, promise); - } - return promise; - async function inner() { - return await bufferHashAsync( - await path.readBytes(), - ); - } -} diff --git a/install.sh b/install.sh index 263c7a9b..1eaa503b 100755 --- a/install.sh +++ b/install.sh @@ -2,33 +2,173 @@ set -e -u -GHJK_VERSION="${GHJK_VERSION:-v0.2.1}" -GHJK_INSTALLER_URL="${GHJK_INSTALLER_URL:-https://raw.github.com/metatypedev/ghjk/$GHJK_VERSION/install.ts}" -GHJK_SHARE_DIR="${GHJK_SHARE_DIR:-$HOME/.local/share/ghjk}" -DENO_VERSION="${DENO_VERSION:-v1.44.2}" +if ! command -v curl >/dev/null; then + echo "Error: curl is required to install ghjk." 1>&2 + exit 1 +fi + +if ! command -v tar >/dev/null; then + echo "Error: tar is required to install ghjk." 1>&2 + exit 1 +fi + +ORG=metatypedev +REPO=ghjk +EXT=tar.gz +NAME=ghjk +EXE=ghjk + +INSTALLER_URL="https://raw.githubusercontent.com/$ORG/$REPO/main/install.sh" +RELEASE_URL="https://github.com/$ORG/$REPO/releases" + +LATEST_VERSION=$(curl "$RELEASE_URL/latest" -s -L -I -o /dev/null -w '%{url_effective}') +LATEST_VERSION="${LATEST_VERSION##*v}" + +PLATFORM="${PLATFORM:-}" +TMP_DIR=$(mktemp -d) +GHJK_INSTALL_EXEC_DIR="${GHJK_INSTALL_EXEC_DIR:-$HOME/.local/bin}" +VERSION="${VERSION:-$LATEST_VERSION}" # make sure the version is prepended with v -if [ "${DENO_VERSION#"v"}" = "$DENO_VERSION" ]; then - DENO_VERSION="v$DENO_VERSION" +if [ "${VERSION#"v"}" = "$VERSION" ]; then + VERSION="v$VERSION" +fi + +if [ "${PLATFORM:-x}" = "x" ]; then + MACHINE=$(uname -m) + case "$(uname -s | tr '[:upper:]' '[:lower:]')" in + "linux") + case "$MACHINE" in + "arm64"* | "aarch64"* ) PLATFORM='aarch64-unknown-linux-gnu' ;; + *"64") PLATFORM='x86_64-unknown-linux-gnu' ;; + esac + ;; + "darwin") + case "$MACHINE" in + "arm64"* | "aarch64"* ) PLATFORM='aarch64-apple-darwin' ;; + *"64") PLATFORM='x86_64-apple-darwin' ;; + esac + ;; + "msys"*|"cygwin"*|"mingw"*|*"_nt"*|"win"*) + case "$MACHINE" in + *"64") PLATFORM='x86_64-pc-windows-msvc' ;; + esac + ;; + esac + if [ "${PLATFORM:-x}" = "x" ]; then + cat >&2 <&2 </dev/null; then - echo "Error: curl is required to install deno for ghjk." 1>&2 - exit 1 - fi +EOF + if [ ! -d "${GHJK_INSTALL_EXEC_DIR}" ]; then + mkdir -p "$GHJK_INSTALL_EXEC_DIR" + fi - curl -fsSL https://deno.land/x/install/install.sh | DENO_INSTALL="$GHJK_SHARE_DIR" sh -s "$DENO_VERSION" >/dev/null - fi + if [ -w "${GHJK_INSTALL_EXEC_DIR}" ]; then + printf "Press enter to continue (or cancel with Ctrl+C):" >&2 + read -r _throwaway + mv "$TMP_DIR/$EXE" "$GHJK_INSTALL_EXEC_DIR" + else + echo "$GHJK_INSTALL_EXEC_DIR is not writable." + exit 1 + fi fi -export GHJK_SHARE_DIR -export GHJK_INSTALL_DENO_EXEC -"$GHJK_INSTALL_DENO_EXEC" run -A "$GHJK_INSTALLER_URL" +GHJK_INSTALLER_URL="${GHJK_INSTALLER_URL:-https://raw.github.com/$ORG/$REPO/$VERSION/install.ts}" +"$TMP_DIR/$EXE" deno run -A "$GHJK_INSTALLER_URL" + +rm -r "$TMP_DIR" + +SHELL_TYPE=$(basename "$SHELL") + +case $SHELL_TYPE in + bash|zsh|ksh) + SHELL_CONFIG="$HOME/.$SHELL_TYPE"rc + ;; + fish) + SHELL_CONFIG="$HOME/.config/fish/config.fish" + ;; + *) + SHELL_CONFIG="" +esac + +if [ -n "$SHELL_CONFIG" ]; then + printf "\nDetected shell: %s\n" "$SHELL_TYPE" + echo "Do you want to append the new PATH to your configuration ($SHELL_CONFIG)? (y/n): " >&2 + read -r answer + + answer=$(echo "$answer" | tr "[:upper:]" "[:lower:]") + + case $SHELL_TYPE in + bash|zsh|ksh) + APPEND_CMD="export PATH=\"$GHJK_INSTALL_EXEC_DIR:\$PATH\"" + ;; + fish) + APPEND_CMD="fish_add_path $GHJK_INSTALL_EXEC_DIR" + ;; + esac + + if [ "$answer" = "y" ] || [ "$answer" = "yes" ]; then + echo "$APPEND_CMD" >> "$SHELL_CONFIG" + printf "Path added to %s\nRun 'source %s' to apply changes." "$SHELL_CONFIG" "$SHELL_CONFIG" + else + cat < str.trim()) @@ -24,20 +27,11 @@ if (import.meta.main) { // } await install({ ...defaultInstallArgs, - ghjkShareDir: Deno.env.get("GHJK_SHARE_DIR") ?? - defaultInstallArgs.ghjkShareDir, - skipExecInstall: !!skipBinInstall && skipBinInstall != "0" && - skipBinInstall != "false", + ghjkDataDir: Deno.env.get("GHJK_DATA_DIR") ?? + defaultInstallArgs.ghjkDataDir, shellsToHook, - ghjkExecInstallDir: Deno.env.get("GHJK_INSTALL_EXE_DIR") ?? - defaultInstallArgs.ghjkExecInstallDir, - ghjkExecDenoExec: Deno.env.get("GHJK_INSTALL_DENO_EXEC") ?? - defaultInstallArgs.ghjkExecDenoExec, shellHookMarker: Deno.env.get("GHJK_INSTALL_HOOK_MARKER") ?? defaultInstallArgs.shellHookMarker, - noLockfile: !!noLockfile && noLockfile != "0" && noLockfile != "false", - ghjkDenoCacheDir: Deno.env.get("GHJK_INSTALL_DENO_DIR") ?? - defaultInstallArgs.ghjkDenoCacheDir, }); } else { throw new Error( diff --git a/install/bash-preexec.sh b/install/bash-preexec.sh new file mode 100644 index 00000000..29c3f061 --- /dev/null +++ b/install/bash-preexec.sh @@ -0,0 +1,353 @@ +# bash-preexec.sh -- Bash support for ZSH-like 'preexec' and 'precmd' functions. +# https://github.com/rcaloras/bash-preexec +# +# +# 'preexec' functions are executed before each interactive command is +# executed, with the interactive command as its argument. The 'precmd' +# function is executed before each prompt is displayed. +# +# Author: Ryan Caloras (ryan@bashhub.com) +# Forked from Original Author: Glyph Lefkowitz +# +# V0.5.0 +# + +# General Usage: +# +# 1. Source this file at the end of your bash profile so as not to interfere +# with anything else that's using PROMPT_COMMAND. +# +# 2. Add any precmd or preexec functions by appending them to their arrays: +# e.g. +# precmd_functions+=(my_precmd_function) +# precmd_functions+=(some_other_precmd_function) +# +# preexec_functions+=(my_preexec_function) +# +# 3. Consider changing anything using the DEBUG trap or PROMPT_COMMAND +# to use preexec and precmd instead. Preexisting usages will be +# preserved, but doing so manually may be less surprising. +# +# Note: This module requires two Bash features which you must not otherwise be +# using: the "DEBUG" trap, and the "PROMPT_COMMAND" variable. If you override +# either of these after bash-preexec has been installed it will most likely break. + +# Make sure this is bash that's running and return otherwise. +if [[ -z "${BASH_VERSION:-}" ]]; then + return 1; +fi + +# Avoid duplicate inclusion +if [[ -n "${bash_preexec_imported:-}" ]]; then + return 0 +fi +bash_preexec_imported="defined" + +# WARNING: This variable is no longer used and should not be relied upon. +# Use ${bash_preexec_imported} instead. +__bp_imported="${bash_preexec_imported}" + +# Should be available to each precmd and preexec +# functions, should they want it. $? and $_ are available as $? and $_, but +# $PIPESTATUS is available only in a copy, $BP_PIPESTATUS. +# TODO: Figure out how to restore PIPESTATUS before each precmd or preexec +# function. +__bp_last_ret_value="$?" +BP_PIPESTATUS=("${PIPESTATUS[@]}") +__bp_last_argument_prev_command="$_" + +__bp_inside_precmd=0 +__bp_inside_preexec=0 + +# Initial PROMPT_COMMAND string that is removed from PROMPT_COMMAND post __bp_install +__bp_install_string=$'__bp_trap_string="$(trap -p DEBUG)"\ntrap - DEBUG\n__bp_install' + +# Fails if any of the given variables are readonly +# Reference https://stackoverflow.com/a/4441178 +__bp_require_not_readonly() { + local var + for var; do + if ! ( unset "$var" 2> /dev/null ); then + echo "bash-preexec requires write access to ${var}" >&2 + return 1 + fi + done +} + +# Remove ignorespace and or replace ignoreboth from HISTCONTROL +# so we can accurately invoke preexec with a command from our +# history even if it starts with a space. +__bp_adjust_histcontrol() { + local histcontrol + histcontrol="${HISTCONTROL:-}" + histcontrol="${histcontrol//ignorespace}" + # Replace ignoreboth with ignoredups + if [[ "$histcontrol" == *"ignoreboth"* ]]; then + histcontrol="ignoredups:${histcontrol//ignoreboth}" + fi; + export HISTCONTROL="$histcontrol" +} + +# This variable describes whether we are currently in "interactive mode"; +# i.e. whether this shell has just executed a prompt and is waiting for user +# input. It documents whether the current command invoked by the trace hook is +# run interactively by the user; it's set immediately after the prompt hook, +# and unset as soon as the trace hook is run. +__bp_preexec_interactive_mode="" + +# These arrays are used to add functions to be run before, or after, prompts. +declare -a precmd_functions +declare -a preexec_functions + +# Trims leading and trailing whitespace from $2 and writes it to the variable +# name passed as $1 +__bp_trim_whitespace() { + local var=${1:?} text=${2:-} + text="${text#"${text%%[![:space:]]*}"}" # remove leading whitespace characters + text="${text%"${text##*[![:space:]]}"}" # remove trailing whitespace characters + printf -v "$var" '%s' "$text" +} + + +# Trims whitespace and removes any leading or trailing semicolons from $2 and +# writes the resulting string to the variable name passed as $1. Used for +# manipulating substrings in PROMPT_COMMAND +__bp_sanitize_string() { + local var=${1:?} text=${2:-} sanitized + __bp_trim_whitespace sanitized "$text" + sanitized=${sanitized%;} + sanitized=${sanitized#;} + __bp_trim_whitespace sanitized "$sanitized" + printf -v "$var" '%s' "$sanitized" +} + +# This function is installed as part of the PROMPT_COMMAND; +# It sets a variable to indicate that the prompt was just displayed, +# to allow the DEBUG trap to know that the next command is likely interactive. +__bp_interactive_mode() { + __bp_preexec_interactive_mode="on"; +} + + +# This function is installed as part of the PROMPT_COMMAND. +# It will invoke any functions defined in the precmd_functions array. +__bp_precmd_invoke_cmd() { + # Save the returned value from our last command, and from each process in + # its pipeline. Note: this MUST be the first thing done in this function. + __bp_last_ret_value="$?" BP_PIPESTATUS=("${PIPESTATUS[@]}") + + # Don't invoke precmds if we are inside an execution of an "original + # prompt command" by another precmd execution loop. This avoids infinite + # recursion. + if (( __bp_inside_precmd > 0 )); then + return + fi + local __bp_inside_precmd=1 + + # Invoke every function defined in our function array. + local precmd_function + for precmd_function in "${precmd_functions[@]}"; do + + # Only execute this function if it actually exists. + # Test existence of functions with: declare -[Ff] + if type -t "$precmd_function" 1>/dev/null; then + __bp_set_ret_value "$__bp_last_ret_value" "$__bp_last_argument_prev_command" + # Quote our function invocation to prevent issues with IFS + "$precmd_function" + fi + done + + __bp_set_ret_value "$__bp_last_ret_value" +} + +# Sets a return value in $?. We may want to get access to the $? variable in our +# precmd functions. This is available for instance in zsh. We can simulate it in bash +# by setting the value here. +__bp_set_ret_value() { + return ${1:-} +} + +__bp_in_prompt_command() { + + local prompt_command_array + IFS=$'\n;' read -rd '' -a prompt_command_array <<< "${PROMPT_COMMAND:-}" + + local trimmed_arg + __bp_trim_whitespace trimmed_arg "${1:-}" + + local command trimmed_command + for command in "${prompt_command_array[@]:-}"; do + __bp_trim_whitespace trimmed_command "$command" + if [[ "$trimmed_command" == "$trimmed_arg" ]]; then + return 0 + fi + done + + return 1 +} + +# This function is installed as the DEBUG trap. It is invoked before each +# interactive prompt display. Its purpose is to inspect the current +# environment to attempt to detect if the current command is being invoked +# interactively, and invoke 'preexec' if so. +__bp_preexec_invoke_exec() { + + # Save the contents of $_ so that it can be restored later on. + # https://stackoverflow.com/questions/40944532/bash-preserve-in-a-debug-trap#40944702 + __bp_last_argument_prev_command="${1:-}" + # Don't invoke preexecs if we are inside of another preexec. + if (( __bp_inside_preexec > 0 )); then + return + fi + local __bp_inside_preexec=1 + + # Checks if the file descriptor is not standard out (i.e. '1') + # __bp_delay_install checks if we're in test. Needed for bats to run. + # Prevents preexec from being invoked for functions in PS1 + if [[ ! -t 1 && -z "${__bp_delay_install:-}" ]]; then + return + fi + + if [[ -n "${COMP_LINE:-}" ]]; then + # We're in the middle of a completer. This obviously can't be + # an interactively issued command. + return + fi + if [[ -z "${__bp_preexec_interactive_mode:-}" ]]; then + # We're doing something related to displaying the prompt. Let the + # prompt set the title instead of me. + return + else + # If we're in a subshell, then the prompt won't be re-displayed to put + # us back into interactive mode, so let's not set the variable back. + # In other words, if you have a subshell like + # (sleep 1; sleep 2) + # You want to see the 'sleep 2' as a set_command_title as well. + if [[ 0 -eq "${BASH_SUBSHELL:-}" ]]; then + __bp_preexec_interactive_mode="" + fi + fi + + if __bp_in_prompt_command "${BASH_COMMAND:-}"; then + # If we're executing something inside our prompt_command then we don't + # want to call preexec. Bash prior to 3.1 can't detect this at all :/ + __bp_preexec_interactive_mode="" + return + fi + + local this_command + this_command=$( + export LC_ALL=C + HISTTIMEFORMAT= builtin history 1 | sed '1 s/^ *[0-9][0-9]*[* ] //' + ) + + # Sanity check to make sure we have something to invoke our function with. + if [[ -z "$this_command" ]]; then + return + fi + + # Invoke every function defined in our function array. + local preexec_function + local preexec_function_ret_value + local preexec_ret_value=0 + for preexec_function in "${preexec_functions[@]:-}"; do + + # Only execute each function if it actually exists. + # Test existence of function with: declare -[fF] + if type -t "$preexec_function" 1>/dev/null; then + __bp_set_ret_value ${__bp_last_ret_value:-} + # Quote our function invocation to prevent issues with IFS + "$preexec_function" "$this_command" + preexec_function_ret_value="$?" + if [[ "$preexec_function_ret_value" != 0 ]]; then + preexec_ret_value="$preexec_function_ret_value" + fi + fi + done + + # Restore the last argument of the last executed command, and set the return + # value of the DEBUG trap to be the return code of the last preexec function + # to return an error. + # If `extdebug` is enabled a non-zero return value from any preexec function + # will cause the user's command not to execute. + # Run `shopt -s extdebug` to enable + __bp_set_ret_value "$preexec_ret_value" "$__bp_last_argument_prev_command" +} + +__bp_install() { + # Exit if we already have this installed. + if [[ "${PROMPT_COMMAND:-}" == *"__bp_precmd_invoke_cmd"* ]]; then + return 1; + fi + + trap '__bp_preexec_invoke_exec "$_"' DEBUG + + # Preserve any prior DEBUG trap as a preexec function + local prior_trap=$(sed "s/[^']*'\(.*\)'[^']*/\1/" <<<"${__bp_trap_string:-}") + unset __bp_trap_string + if [[ -n "$prior_trap" ]]; then + eval '__bp_original_debug_trap() { + '"$prior_trap"' + }' + preexec_functions+=(__bp_original_debug_trap) + fi + + # Adjust our HISTCONTROL Variable if needed. + __bp_adjust_histcontrol + + # Issue #25. Setting debug trap for subshells causes sessions to exit for + # backgrounded subshell commands (e.g. (pwd)& ). Believe this is a bug in Bash. + # + # Disabling this by default. It can be enabled by setting this variable. + if [[ -n "${__bp_enable_subshells:-}" ]]; then + + # Set so debug trap will work be invoked in subshells. + set -o functrace > /dev/null 2>&1 + shopt -s extdebug > /dev/null 2>&1 + fi; + + local existing_prompt_command + # Remove setting our trap install string and sanitize the existing prompt command string + existing_prompt_command="${PROMPT_COMMAND:-}" + existing_prompt_command="${existing_prompt_command//$__bp_install_string[;$'\n']}" # Edge case of appending to PROMPT_COMMAND + existing_prompt_command="${existing_prompt_command//$__bp_install_string}" + __bp_sanitize_string existing_prompt_command "$existing_prompt_command" + + # Install our hooks in PROMPT_COMMAND to allow our trap to know when we've + # actually entered something. + PROMPT_COMMAND=$'__bp_precmd_invoke_cmd\n' + if [[ -n "$existing_prompt_command" ]]; then + PROMPT_COMMAND+=${existing_prompt_command}$'\n' + fi; + PROMPT_COMMAND+='__bp_interactive_mode' + + # Add two functions to our arrays for convenience + # of definition. + precmd_functions+=(precmd) + preexec_functions+=(preexec) + + # Invoke our two functions manually that were added to $PROMPT_COMMAND + __bp_precmd_invoke_cmd + __bp_interactive_mode +} + +# Sets an installation string as part of our PROMPT_COMMAND to install +# after our session has started. This allows bash-preexec to be included +# at any point in our bash profile. +__bp_install_after_session_init() { + # bash-preexec needs to modify these variables in order to work correctly + # if it can't, just stop the installation + __bp_require_not_readonly PROMPT_COMMAND HISTCONTROL HISTTIMEFORMAT || return + + local sanitized_prompt_command + __bp_sanitize_string sanitized_prompt_command "${PROMPT_COMMAND:-}" + if [[ -n "$sanitized_prompt_command" ]]; then + PROMPT_COMMAND=${sanitized_prompt_command}$'\n' + fi; + PROMPT_COMMAND+=${__bp_install_string} +} + +# Run our install so long as we're not delaying it. +if [[ -z "${__bp_delay_install:-}" ]]; then + __bp_install_after_session_init +fi; diff --git a/install/ghjk.sh b/install/ghjk.sh deleted file mode 100644 index 50ac141b..00000000 --- a/install/ghjk.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/sh - -export GHJK_SHARE_DIR="${GHJK_SHARE_DIR:-__GHJK_SHARE_DIR__}" -export DENO_DIR="${GHJK_DENO_DIR:-__DENO_CACHE_DIR}" -export DENO_NO_UPDATE_CHECK=1 -GHJK_MAIN_URL="${GHJK_MAIN_URL:-__MAIN_TS_URL__}" - -# NOTE: avoid putting too much in here as this is only one -# method of getting the ghjk bin which is all utlimately optional -# anyways. - -# NOTE: keep this in sync with impls in install/exec.ts - -# if ghjkfile var is set, set the GHJK_DIR overriding -# any set by the user -if [ -n "${GHJKFILE+x}" ]; then - - GHJK_DIR="$(dirname "$GHJKFILE")/.ghjk" - -# if both GHJKFILE and GHJK_DIR are unset -elif [ -z "${GHJK_DIR+x}" ]; then - - # look for ghjk dirs in parents - cur_dir=$PWD - while true; do - if [ -d "$cur_dir/.ghjk" ] || [ -e "$cur_dir/ghjk.ts" ]; then - GHJK_DIR="$cur_dir/.ghjk" - break - fi - # recursively look in parent directory - next_cur_dir="$(dirname "$cur_dir")" - if [ "$next_cur_dir" = / ] && [ "$cur_dir" = "/" ]; then - break - fi - cur_dir="$next_cur_dir" - done - -fi - -if [ -n "${GHJK_DIR+x}" ]; then - - export GHJK_DIR - mkdir -p "$GHJK_DIR" - lock_flag="--lock $GHJK_DIR/deno.lock" - -else - - lock_flag="--no-lock" - -fi - -# we don't want to quote $lock_flag as it's not exactly a single -# string param to deno -# shellcheck disable=SC2086 -exec __DENO_EXEC__ run __UNSTABLE_FLAGS__ -A $lock_flag $GHJK_MAIN_URL "$@" diff --git a/install/hook.fish b/install/hook.fish index 072c19fe..0de6ecde 100644 --- a/install/hook.fish +++ b/install/hook.fish @@ -1,15 +1,24 @@ function __ghjk_get_mtime_ts switch (uname -s | tr '[:upper:]' '[:lower:]') case "linux" - stat -c "%Y" $argv + stat -c "%.Y" $argv case "darwin" - stat -f "%Sm" -t "%s" $argv + # darwin stat doesn't support ms since epoch so we bring out the big guns + deno eval 'console.log((await Deno.stat(Deno.args[0])).mtime.getTime())' $argv + # stat -f "%Sm" -t "%s" $argv case "*" - stat -c "%Y" $argv + stat -c "%.Y" $argv end end -function ghjk_reload --on-variable PWD --on-event ghjk_env_dir_change +function ghjk_hook --on-variable PWD + # to be consistent with the posix shells + # we avoid reloading the env on PWD changes + # if not in an interactive shell + if not status is-interactive; and test "$argv" = "VARIABLE SET PWD"; + return + end + # precedence is gven to argv over GHJK_ENV set --local next_env $argv[1] test -z $next_env; and set next_env "$GHJK_ENV" @@ -97,14 +106,22 @@ function __ghjk_preexec --on-event fish_preexec # exists if set --query GHJK_NEXTFILE; and test -f "$GHJK_NEXTFILE"; - ghjk_reload (cat $GHJK_NEXTFILE) + ghjk_hook (cat $GHJK_NEXTFILE) rm "$GHJK_NEXTFILE" # activate script has reloaded else if set --query GHJK_LAST_ENV_DIR; + and test -e $GHJK_LAST_ENV_DIR/activate.fish; and test (__ghjk_get_mtime_ts $GHJK_LAST_ENV_DIR/activate.fish) -gt $GHJK_LAST_ENV_DIR_MTIME; - ghjk_reload + ghjk_hook end end -ghjk_reload + +if set --query GHJK_AUTO_HOOK; and begin; + test $GHJK_AUTO_HOOK != "0"; + and test $GHJK_AUTO_HOOK != "false"; + and test $GHJK_AUTO_HOOK != "" +end; or status is-interactive; + ghjk_hook +end diff --git a/install/hook.sh b/install/hook.sh index 7a439206..f943e463 100644 --- a/install/hook.sh +++ b/install/hook.sh @@ -7,7 +7,9 @@ __ghjk_get_mtime_ts () { stat -c "%Y" "$1" ;; "darwin") - stat -f "%Sm" -t "%s" "$1" + # darwin stat doesn't support ms since epoch so we bring out the big guns + deno eval 'console.log((await Deno.stat(Deno.args[0])).mtime.getTime())' "$1" + # stat -f "%Sm" -t "%s" "$1" ;; "*") stat -c "%Y" "$1" @@ -15,7 +17,7 @@ __ghjk_get_mtime_ts () { esac } -ghjk_reload() { +ghjk_hook() { # precedence is given to argv over GHJK_ENV # which's usually the current active env @@ -99,21 +101,36 @@ precmd() { # we ignore previously loaded GHJK_ENV when switching # directories unset GHJK_ENV - ghjk_reload + ghjk_hook export GHJK_LAST_PWD="$PWD" # -nextfile exists elif [ -f "$GHJK_NEXTFILE" ]; then - ghjk_reload "$(cat "$GHJK_NEXTFILE")" + ghjk_hook "$(cat "$GHJK_NEXTFILE")" rm "$GHJK_NEXTFILE" # - the env dir loader mtime changes - elif [ -n "${GHJK_LAST_ENV_DIR+x}" ] && [ "$(__ghjk_get_mtime_ts "$GHJK_LAST_ENV_DIR/activate.sh")" -gt "$GHJK_LAST_ENV_DIR_MTIME" ]; then + elif [ -n "${GHJK_LAST_ENV_DIR+x}" ] && [ -e "$GHJK_LAST_ENV_DIR/activate.sh" ] && [ "$(__ghjk_get_mtime_ts "$GHJK_LAST_ENV_DIR/activate.sh")" -gt "$GHJK_LAST_ENV_DIR_MTIME" ]; then - ghjk_reload + ghjk_hook fi } -ghjk_reload +case "$-" in + *i*) # if the shell variables contain "i" + # only run the hook in interactive mode + # and GHJK_AUTO_HOOK is unset/false + if [ -z "$GHJK_AUTO_HOOK" ] || [ "$GHJK_AUTO_HOOK" != "0" ] && [ "$GHJK_AUTO_HOOK" != "false" ]; then + ghjk_hook + fi + ;; + *) + # also run the hook if GHJK_AUTO_HOOK is set + if [ -n "${GHJK_AUTO_HOOK+x}" ] && [ "$GHJK_AUTO_HOOK" != "0" ] && [ "$GHJK_AUTO_HOOK" != "false" ]; then + ghjk_hook + fi + : + ;; +esac diff --git a/install/mod.ts b/install/mod.ts index d63eca51..fb764b03 100644 --- a/install/mod.ts +++ b/install/mod.ts @@ -5,19 +5,12 @@ // relying on --frozen-lockfile import getLogger from "../utils/logger.ts"; -import { $, dirs, importRaw } from "../utils/mod.ts"; +import { $, importRaw } from "../utils/mod.ts"; import type { Path } from "../utils/mod.ts"; +import { xdg } from "../deps/install.ts"; const logger = getLogger(import.meta); -/** - * Deno unstable flags needed for ghjk host. - */ -export const unstableFlags = [ - "--unstable-kv", - "--unstable-worker-options", -]; - // TODO: calculate and add integrity hashes to these raw imports // as they won't be covered by deno.lock // - use pre-commit-hook plus ghjk tasks to do find+replace @@ -39,7 +32,7 @@ const getHooksVfs = async () => ({ "env.bash": [ "# importing bash-preexec, see the ghjk hook at then end\n\n", await importRaw( - "https://raw.githubusercontent.com/rcaloras/bash-preexec/0.5.0/bash-preexec.sh", + import.meta.resolve("./bash-preexec.sh"), ), await importRaw(import.meta.resolve("./hook.sh")), ].join("\n"), @@ -104,51 +97,37 @@ async function filterAddContent( interface InstallArgs { homeDir: string; - ghjkShareDir: string; + ghjkDataDir: string; shellsToHook?: string[]; /** The mark used when adding the hook to the user's shell rcs. * Override to allow multiple hooks in your rc. */ shellHookMarker: string; - /** - * The ghjk bin is optional, one can always invoke it - * using `deno run --flags uri/to/ghjk/main.ts`; - */ - skipExecInstall: boolean; - /** The directory in which to install the ghjk exec - * Preferrably, one that's in PATH - */ - ghjkExecInstallDir: string; - /** - * The deno exec to be used by the ghjk executable - * by default will be "deno" i.e. whatever in $PATH that resolves that to. - */ - ghjkExecDenoExec: string; - /** - * The cache dir to use by the ghjk deno installation. - */ - ghjkDenoCacheDir?: string; - /** - * Disable using a lockfile for the ghjk command - */ - noLockfile: boolean; +} + +function getHomeDir() { + switch (Deno.build.os) { + case "linux": + case "darwin": + return Deno.env.get("HOME") ?? null; + case "windows": + return Deno.env.get("USERPROFILE") ?? null; + default: + return null; + } +} +const homeDir = getHomeDir(); +if (!homeDir) { + throw new Error("cannot find home dir"); } export const defaultInstallArgs: InstallArgs = { - ghjkShareDir: $.path(dirs().shareDir).resolve("ghjk").toString(), - homeDir: dirs().homeDir, + // remove first the xdg.data suffix added in windows by lib + ghjkDataDir: $.path(xdg.data().replace("xdg.data", "")).resolve("ghjk") + .toString(), + homeDir, shellsToHook: [], shellHookMarker: "ghjk-hook-default", - skipExecInstall: true, - // TODO: respect xdg dirs - ghjkExecInstallDir: $.path(dirs().homeDir).resolve(".local", "bin") - .toString(), - ghjkExecDenoExec: Deno.execPath(), - /** - * the default behvaior kicks in with ghjkDenoCacheDir is falsy - * ghjkDenoCacheDir: undefined, - */ - noLockfile: false, }; const shellConfig: Record = { @@ -165,14 +144,14 @@ export async function install( if (Deno.build.os == "windows") { throw new Error("windows is not yet supported, please use wsl"); } - const ghjkShareDir = $.path(Deno.cwd()) - .resolve(args.ghjkShareDir); + const ghjkDataDir = $.path(Deno.cwd()) + .resolve(args.ghjkDataDir); - logger.info("unpacking vfs", { ghjkShareDir }); + logger.info("unpacking vfs", { ghjkDataDir }); await unpackVFS( await getHooksVfs(), - ghjkShareDir, - [[/__GHJK_SHARE_DIR__/g, ghjkShareDir.toString()]], + ghjkDataDir, + [[/__GHJK_DATA_DIR__/g, ghjkDataDir.toString()]], ); for (const shell of args.shellsToHook ?? Object.keys(shellConfig)) { const { homeDir } = args; @@ -188,7 +167,7 @@ export async function install( continue; } logger.info("installing hook", { - ghjkShareDir, + ghjkDataDir, shell, marker: args.shellHookMarker, rcPath, @@ -196,54 +175,7 @@ export async function install( await filterAddContent( rcPath, new RegExp(args.shellHookMarker, "g"), - `. ${ghjkShareDir}/env.${shell} # ${args.shellHookMarker}`, + `. ${ghjkDataDir}/env.${shell} # ${args.shellHookMarker}`, ); } - - if (!args.skipExecInstall) { - switch (Deno.build.os) { - case "linux": - case "freebsd": - case "solaris": - case "illumos": - case "darwin": { - const installDir = await $.path(args.ghjkExecInstallDir).ensureDir(); - const exePath = installDir.resolve(`ghjk`); - logger.info("installing executable", { exePath }); - - // use an isolated cache by default - const denoCacheDir = args.ghjkDenoCacheDir - ? $.path(args.ghjkDenoCacheDir) - : ghjkShareDir.resolve("deno"); - await exePath.writeText( - (await importRaw(import.meta.resolve("./ghjk.sh"))) - .replaceAll( - "__GHJK_SHARE_DIR__", - ghjkShareDir.toString(), - ) - .replaceAll( - "__DENO_CACHE_DIR", - denoCacheDir.toString(), - ) - .replaceAll( - "__DENO_EXEC__", - args.ghjkExecDenoExec, - ) - .replaceAll( - "__UNSTABLE_FLAGS__", - unstableFlags.join(" "), - ) - .replaceAll( - "__MAIN_TS_URL__", - import.meta.resolve("../main.ts"), - ), - { mode: 0o700 }, - ); - break; - } - default: - throw new Error(`${Deno.build.os} is not yet supported`); - } - } - logger.info("install success"); } diff --git a/install/utils.ts b/install/utils.ts index 1f5bb9b5..a6796845 100644 --- a/install/utils.ts +++ b/install/utils.ts @@ -1,44 +1,31 @@ //! Please keep these in sync with `./ghjk.ts` import type { GhjkCtx } from "../modules/types.ts"; -import { unstableFlags } from "./mod.ts"; /** * Returns a simple posix function to invoke the ghjk CLI. + * This shim assumes it's running inside the ghjk embedded deno runtime. */ export function ghjk_sh( gcx: GhjkCtx, - denoDir: string, functionName = "__ghjk_shim", ) { return `${functionName} () { - GHJK_SHARE_DIR="${gcx.ghjkShareDir}" \\ - DENO_DIR="${denoDir}" \\ - DENO_NO_UPDATE_CHECK=1 \\ GHJK_DIR="${gcx.ghjkDir}" \\ - ${Deno.execPath()} run ${ - unstableFlags.join(" ") - } -A --lock ${gcx.ghjkDir}/deno.lock ${import.meta.resolve("../main.ts")} "$@" + ${Deno.execPath()} "$@" }`; } /** * Returns a simple fish function to invoke the ghjk CLI. + * This shim assumes it's running inside the ghjk embedded deno runtime. */ export function ghjk_fish( gcx: GhjkCtx, - denoDir: string, functionName = "__ghjk_shim", ) { return `function ${functionName} - GHJK_SHARE_DIR="${gcx.ghjkShareDir}" \\ - DENO_DIR="${denoDir}" \\ - DENO_NO_UPDATE_CHECK=1 \\ GHJK_DIR="${gcx.ghjkDir}" \\ - ${Deno.execPath()} run ${ - unstableFlags.join(" ") - } -A --lock ${gcx.ghjkDir}/deno.lock ${ - import.meta.resolve("../main.ts") - } $argv + ${Deno.execPath()} $argv end`; } diff --git a/main.ts b/main.ts deleted file mode 100755 index 35a2f835..00000000 --- a/main.ts +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env -S deno run --unstable-worker-options -A - -import "./setup_logger.ts"; -import { cli } from "./host/mod.ts"; -import { std_path } from "./deps/common.ts"; -import logger from "./utils/logger.ts"; -import { dirs, findEntryRecursive } from "./utils/mod.ts"; - -if (import.meta.main) { - // look for ghjkdir - let ghjkdir = Deno.env.get("GHJK_DIR") ?? - await findEntryRecursive(Deno.cwd(), ".ghjk"); - const ghjkfile = ghjkdir - ? await findEntryRecursive(std_path.dirname(ghjkdir), "ghjk.ts") - : await findEntryRecursive(Deno.cwd(), "ghjk.ts"); - if (!ghjkdir && !ghjkfile) { - logger().warn( - "ghjk could not find any ghjkfiles or ghjkdirs, try creating a `ghjk.ts` script.", - ); - // Deno.exit(2); - } - if (ghjkfile && !ghjkdir) { - ghjkdir = std_path.resolve(std_path.dirname(ghjkfile), ".ghjk"); - } - await cli({ - // FIXME: better - reFlagSet: !!Deno.env.get("GHJK_RE") && - !(["false", "", ""].includes(Deno.env.get("GHJK_RE")!)), - lockedFlagSet: !!Deno.env.get("GHJK_LOCKED") && - !(["false", "", ""].includes(Deno.env.get("GHJK_LOCKED")!)), - - ghjkShareDir: Deno.env.get("GHJK_SHARE_DIR") ?? - dirs().shareDir.resolve("ghjk").toString(), - ghjkfilePath: ghjkfile ? std_path.resolve(Deno.cwd(), ghjkfile) : undefined, - ghjkDirPath: ghjkdir ? std_path.resolve(Deno.cwd(), ghjkdir) : undefined, - }); -} else { - throw new Error( - `unexpected context: this module is an entrypoint. If you want to programmatically invoke the ghjk cli, import \`cli\` from ${ - import.meta.resolve("./host/mod.ts") - }`, - ); -} diff --git a/mod.ts b/mod.ts index 891c777a..681b2373 100644 --- a/mod.ts +++ b/mod.ts @@ -1,4 +1,4 @@ -//! This module is intended to be re-exported by `ghjk.ts` config scripts. +//! The primary import used by `ghjk.ts` ghjkfiles. // TODO: harden most of the items in here @@ -51,6 +51,14 @@ export type AddTask = { ): string; }; +/** + * Define and register multiple tasks. + */ +export type AddTasks = { + (args: (DenoTaskDefArgs | TaskFn)[]): string[]; + (args: Record>): string[]; +}; + export type FileArgs = { /** * The env to activate by default. When entering the working @@ -111,6 +119,10 @@ type DenoFileKnobs = { * {@inheritdoc AddTask} */ task: AddTask; + /** + * {@inheritdoc AddTasks} + */ + tasks: AddTasks; /** * {@inheritDoc AddEnv} */ @@ -216,6 +228,34 @@ export const file = Object.freeze(function file( ), }); + function task( + nameOrArgsOrFn: string | DenoTaskDefArgs | TaskFn, + argsOrFn?: Omit | TaskFn, + argsMaybe?: Omit, + ) { + let args: DenoTaskDefArgs; + if (typeof nameOrArgsOrFn == "object") { + args = nameOrArgsOrFn; + } else if (typeof nameOrArgsOrFn == "function") { + args = { + ...(argsOrFn ?? {}), + fn: nameOrArgsOrFn, + }; + } else if (typeof argsOrFn == "object") { + args = { ...argsOrFn, name: nameOrArgsOrFn }; + } else if (argsOrFn) { + args = { + ...(argsMaybe ?? {}), + name: nameOrArgsOrFn, + fn: argsOrFn, + }; + } else { + args = { + name: nameOrArgsOrFn, + }; + } + return builder.addTask({ ...args, ty: "denoFile@v1" }); + } // we return a bunch of functions here // to ease configuring the main environment // including overloads @@ -226,33 +266,18 @@ export const file = Object.freeze(function file( mainEnv.install(...configs); }, - task( - nameOrArgsOrFn: string | DenoTaskDefArgs | TaskFn, - argsOrFn?: Omit | TaskFn, - argsMaybe?: Omit, + task, + + tasks( + defs: + | (DenoTaskDefArgs | TaskFn)[] + | Record>, ) { - let args: DenoTaskDefArgs; - if (typeof nameOrArgsOrFn == "object") { - args = nameOrArgsOrFn; - } else if (typeof nameOrArgsOrFn == "function") { - args = { - ...(argsOrFn ?? {}), - fn: nameOrArgsOrFn, - }; - } else if (typeof argsOrFn == "object") { - args = { ...argsOrFn, name: nameOrArgsOrFn }; - } else if (argsOrFn) { - args = { - ...(argsMaybe ?? {}), - name: nameOrArgsOrFn, - fn: argsOrFn, - }; + if (Array.isArray(defs)) { + return defs.map((def) => task(def)); } else { - args = { - name: nameOrArgsOrFn, - }; + return Object.entries(defs).map(([key, val]) => task(key, val)); } - return builder.addTask({ ...args, ty: "denoFile@v1" }); }, env( diff --git a/modules/envs/mod.ts b/modules/envs/mod.ts index 6258f72b..996970ad 100644 --- a/modules/envs/mod.ts +++ b/modules/envs/mod.ts @@ -1,6 +1,6 @@ export * from "./types.ts"; -import { cliffy_cmd, zod } from "../../deps/cli.ts"; +import { zod } from "../../deps/cli.ts"; import { $, detectShellPath, Json, unwrapZodRes } from "../../utils/mod.ts"; import validators from "./types.ts"; import type { @@ -20,6 +20,7 @@ import type { import { buildInstallGraph, syncCtxFromGhjk } from "../ports/sync.ts"; import { getEnvsCtx } from "./inter.ts"; import { getTasksCtx } from "../tasks/inter.ts"; +import { CliCommand } from "../../src/deno_systems/types.ts"; export type EnvsCtx = { activeEnv: string; @@ -33,9 +34,8 @@ const lockValidator = zod.object({ type EnvsLockEnt = zod.infer; -export class EnvsModule extends ModuleBase { - processManifest( - gcx: GhjkCtx, +export class EnvsModule extends ModuleBase { + override loadConfig( manifest: ModuleManifest, _bb: Blackboard, _lockEnt: EnvsLockEnt | undefined, @@ -52,20 +52,18 @@ export class EnvsModule extends ModuleBase { const setEnv = Deno.env.get("GHJK_ENV"); const activeEnv = setEnv && setEnv != "" ? setEnv : config.defaultEnv; - const envsCtx = getEnvsCtx(gcx); - envsCtx.activeEnv = activeEnv; - envsCtx.config = config; + const ecx = getEnvsCtx(this.gcx); + ecx.activeEnv = activeEnv; + ecx.config = config; for (const [name, key] of Object.entries(config.envsNamed)) { - envsCtx.keyToName[key] = [name, ...(envsCtx.keyToName[key] ?? [])]; + ecx.keyToName[key] = [name, ...(ecx.keyToName[key] ?? [])]; } - - return Promise.resolve(envsCtx); } - commands( - gcx: GhjkCtx, - ecx: EnvsCtx, - ) { + override commands(): CliCommand[] { + const gcx = this.gcx; + const ecx = getEnvsCtx(this.gcx); + function envKeyArgs( args: { taskKeyMaybe?: string; @@ -92,20 +90,32 @@ export class EnvsModule extends ModuleBase { : { envKey: envKeyMaybe ?? ecx.activeEnv }; } - return { - envs: new cliffy_cmd - .Command() - .description("Envs module, reproducable posix shells environments.") - .alias("e") - // .alias("env") - .action(function () { - this.showHelp(); - }) - .command( - "ls", - new cliffy_cmd.Command() - .description("List environments defined in the ghjkfile.") - .action(() => { + const commonFlags: CliCommand["flags"] = { + taskEnv: { + short: "t", + long: "task-env", + value_name: "TASK NAME", + help: "Activate the environment used by the named task", + exclusive: true, + }, + }; + + const commonArgs: CliCommand["args"] = { + envKey: { + value_name: "ENV KEY", + }, + }; + + return [ + { + name: "envs", + visible_aliases: ["e"], + about: "Envs module, reproducable posix shells environments.", + sub_commands: [ + { + name: "ls", + about: "List environments defined in the ghjkfile.", + action: () => { // deno-lint-ignore no-console console.log( Object.entries(ecx.config.envsNamed) @@ -118,91 +128,115 @@ export class EnvsModule extends ModuleBase { }) .join("\n"), ); - }), - ) - .command( - "activate", - new cliffy_cmd.Command() - .description(`Activate an environment. - -- If no [envName] is specified and no env is currently active, this activates the configured default env [${ecx.config.defaultEnv}].`) - .arguments("[envName:string]") - .option( - "-t, --task-env ", - "Synchronize to the environment used by the named task", - { standalone: true }, - ) - .action(async function ({ taskEnv }, envKeyMaybe) { + }, + }, + { + name: "activate", + about: `Activate an environment.`, + before_long_help: + `- If no ENV KEY is specified and no env is currently active, this activates the configured default env [${ecx.config.defaultEnv}].`, + flags: { + ...commonFlags, + }, + args: { + ...commonArgs, + }, + action: async function ( + { + flags: { taskEnv: taskKeyMaybe }, + args: { envKey: envKeyMaybe }, + }, + ) { const { envKey } = envKeyArgs({ - taskKeyMaybe: taskEnv, - envKeyMaybe, + taskKeyMaybe: taskKeyMaybe as string, + envKeyMaybe: (Array.isArray(envKeyMaybe) + ? envKeyMaybe[0] + : envKeyMaybe) as string, }); await activateEnv(envKey); - }), - ) - .command( - "cook", - new cliffy_cmd.Command() - .description(`Cooks the environment to a posix shell. - -- If no [envName] is specified, this will cook the active env [${ecx.activeEnv}]`) - .arguments("[envName:string]") - .option( - "-t, --task-env ", - "Synchronize to the environment used by the named task", - { standalone: true }, - ) - .action(async function ({ taskEnv }, envKeyMaybe) { + }, + }, + { + name: "cook", + about: `Cooks the environment to a posix shell.`, + before_long_help: + `- If no ENV KEY is specified, this will cook the active env [${ecx.activeEnv}]`, + flags: { + ...commonFlags, + }, + args: { + ...commonArgs, + }, + action: async function ( + { + flags: { taskEnv: taskKeyMaybe }, + args: { envKey: envKeyMaybe }, + }, + ) { const { envKey, envName } = envKeyArgs({ - taskKeyMaybe: taskEnv, - envKeyMaybe, + taskKeyMaybe: taskKeyMaybe as string, + envKeyMaybe: (Array.isArray(envKeyMaybe) + ? envKeyMaybe[0] + : envKeyMaybe) as string, }); await reduceAndCookEnv(gcx, ecx, envKey, envName ?? envKey); - }), - ) - .command( - "show", - new cliffy_cmd.Command() - .description(`Show details about an environment. + }, + }, + { + name: "show", + about: `Cooks the environment to a posix shell.`, + before_long_help: `Show details about an environment. -- If no [envName] is specified, this shows details of the active env [${ecx.activeEnv}]. -- If no [envName] is specified and no env is active, this shows details of the default env [${ecx.config.defaultEnv}]. - `) - .arguments("[envName:string]") - .option( - "-t, --task-env ", - "Synchronize to the environment used by the named task", - { standalone: true }, - ) - .action(async function ({ taskEnv }, envKeyMaybe) { +- If no ENV KEY is specified, this shows details of the active env [${ecx.activeEnv}]. +- If no ENV KEY is specified and no env is active, this shows details of the default env [${ecx.config.defaultEnv}].`, + flags: { + ...commonFlags, + }, + args: { + ...commonArgs, + }, + action: async function ( + { + flags: { taskEnv: taskKeyMaybe }, + args: { envKey: envKeyMaybe }, + }, + ) { const { envKey } = envKeyArgs({ - taskKeyMaybe: taskEnv, - envKeyMaybe, + taskKeyMaybe: taskKeyMaybe as string, + envKeyMaybe: (Array.isArray(envKeyMaybe) + ? envKeyMaybe[0] + : envKeyMaybe) as string, }); const env = ecx.config.envs[envKey]; if (!env) { - throw new Error(`no env found under "${envKeyMaybe}"`); + throw new Error(`no env found under "${envKey}"`); } // deno-lint-ignore no-console console.log($.inspect(await showableEnv(gcx, env, envKey))); - }), - ), - sync: new cliffy_cmd.Command() - .description(`Synchronize your shell to what's in your config. - -Cooks and activates an environment. -- If no [envName] is specified and no env is currently active, this syncs the configured default env [${ecx.config.defaultEnv}]. -- If the environment is already active, this doesn't launch a new shell.`) - .arguments("[envName:string]") - .option( - "-t, --task-env ", - "Synchronize to the environment used by the named task", - { standalone: true }, - ) - .action(async function ({ taskEnv }, envKeyMaybe) { + }, + }, + ], + }, + { + name: "sync", + about: "Synchronize your shell to what's in your config.", + before_long_help: `Cooks and activates an environment. +- If no ENV KEY is specified and no env is currently active, this syncs the configured default env [${ecx.config.defaultEnv}]. +- If the environment is already active, this doesn't launch a new shell.`, + flags: { + ...commonFlags, + }, + args: { + ...commonArgs, + }, + action: async function ( + { flags: { taskEnv: taskKeyMaybe }, args: { envKey: envKeyMaybe } }, + ) { const { envKey, envName } = envKeyArgs({ - taskKeyMaybe: taskEnv, - envKeyMaybe, + taskKeyMaybe: taskKeyMaybe as string, + envKeyMaybe: (Array.isArray(envKeyMaybe) + ? envKeyMaybe[0] + : envKeyMaybe) as string, }); await reduceAndCookEnv( gcx, @@ -211,14 +245,12 @@ Cooks and activates an environment. envName ?? envKey, ); await activateEnv(envKey); - }), - }; + }, + }, + ]; } - loadLockEntry( - _gcx: GhjkCtx, - raw: Json, - ) { + loadLockEntry(raw: Json) { const entry = lockValidator.parse(raw); if (entry.version != "0") { @@ -227,10 +259,7 @@ Cooks and activates an environment. return entry; } - genLockEntry( - _gcx: GhjkCtx, - _tcx: EnvsCtx, - ) { + genLockEntry() { return { version: "0", }; diff --git a/modules/envs/posix.ts b/modules/envs/posix.ts index 5e775f50..323fa055 100644 --- a/modules/envs/posix.ts +++ b/modules/envs/posix.ts @@ -202,7 +202,7 @@ async function writeActivators( onExitHooks: [string, string[]][], ) { const ghjkDirVar = "_ghjk_dir"; - const shareDirVar = "_ghjk_share_dir"; + const dataDirVar = "_ghjk_data_dir"; pathVars = { ...Object.fromEntries( Object.entries(pathVars).map(( @@ -211,7 +211,7 @@ async function writeActivators( key, val .replace(gcx.ghjkDir.toString(), "$" + ghjkDirVar) - .replace(gcx.ghjkShareDir.toString(), "$" + shareDirVar), + .replace(gcx.ghjkDataDir.toString(), "$" + dataDirVar), ]), ), }; @@ -227,9 +227,6 @@ async function writeActivators( .join(" ").replaceAll("'", "'\\''") ); - // ghjk.sh sets the DENO_DIR so we can usually - // assume it's set - const denoDir = Deno.env.get("DENO_DIR") ?? ""; const scripts = { // // posix shell version @@ -238,16 +235,26 @@ async function writeActivators( `# shellcheck disable=SC2016`, `# SC2016: disabled because single quoted expressions are used for the cleanup scripts`, ``, - `if [ -n "$\{GHJK_CLEANUP_POSIX+x}" ]; then`, - ` eval "$GHJK_CLEANUP_POSIX"`, - `fi`, - `export GHJK_CLEANUP_POSIX="";`, + `# this file bust be sourced from an existing sh/bash/zsh session using the \`source\` command`, + `# it cannot be executed directly`, + ``, + `ghjk_deactivate () {`, + ` if [ -n "$\{GHJK_CLEANUP_POSIX+x}" ]; then`, + ` eval "$GHJK_CLEANUP_POSIX"`, + ` unset GHJK_CLEANUP_POSIX`, + ` fi`, + `}`, + `ghjk_deactivate`, + ``, ``, `# the following variables are used to make the script more human readable`, `${ghjkDirVar}="${gcx.ghjkDir.toString()}"`, - `${shareDirVar}="${gcx.ghjkShareDir.toString()}"`, + `${dataDirVar}="${gcx.ghjkDataDir.toString()}"`, ``, + `export GHJK_CLEANUP_POSIX="";`, `# env vars`, + `# we keep track of old values before this script is run`, + `# so that we can restore them on cleanup`, ...Object.entries(envVars).flatMap(([key, val]) => { const safeVal = val.replaceAll("\\", "\\\\").replaceAll("'", "'\\''"); // avoid triggering unbound variable if -e is set @@ -273,7 +280,7 @@ async function writeActivators( // i.e. export KEY='OLD $VALUE OF KEY' // but $VALUE won't be expanded when the cleanup actually runs // we also unset the key if it wasn't previously set - `$([ -z "$\{${key}+x}" ] && echo 'export ${key}= '\\'"$\{${key}:-unreachable}""';" || echo 'unset ${key};');`, + `$([ -z "$\{${key}+x}" ] && echo 'unset ${key};' || echo 'export ${key}='\\'"$\{${key}:-unreachable}""';");`, `export ${key}='${safeVal}';`, ``, ]; @@ -289,17 +296,14 @@ async function writeActivators( // FIXME: we're allowing expansion in the value to allow // readable $ghjkDirVar usage // (for now safe since all paths are created within ghjk) - `export ${key}="${safeVal}:$${key}";`, + `export ${key}="${safeVal}:$\{${key}-}";`, ``, ]; }), ``, `# hooks that want to invoke ghjk are made to rely`, - `# on this shim to improving latency`, - // the ghjk executable is itself a shell script - // which execs deno, we remove the middleman here - // also, the ghjk executable is optional - ghjk_sh(gcx, denoDir, ghjkShimName), + `# on this shim to improve reliablity`, + ghjk_sh(gcx, ghjkShimName), ``, `# only run the hooks in interactive mode`, `case "$-" in`, @@ -323,25 +327,33 @@ async function writeActivators( // // fish version fish: [ - `if set --query GHJK_CLEANUP_FISH`, - ` eval $GHJK_CLEANUP_FISH`, - ` set --erase GHJK_CLEANUP_FISH`, + `# this file bust be sourced from an existing fish session using the \`source\` command`, + `# it cannot be executed directly`, + ``, + `function ghjk_deactivate`, + ` if set --query GHJK_CLEANUP_FISH`, + ` eval $GHJK_CLEANUP_FISH`, + ` set --erase GHJK_CLEANUP_FISH`, + ` end`, `end`, + `ghjk_deactivate`, ``, `# the following variables are used to make the script more human readable`, `set ${ghjkDirVar} "${gcx.ghjkDir.toString()}"`, - `set ${shareDirVar} "${gcx.ghjkShareDir.toString()}"`, + `set ${dataDirVar} "${gcx.ghjkDataDir.toString()}"`, ``, `# env vars`, + `# we keep track of old values before this script is run`, + `# so that we can restore them on cleanup`, ...Object.entries(envVars).flatMap(([key, val]) => { const safeVal = val.replaceAll("\\", "\\\\").replaceAll("'", "\\'"); // read the comments from the posix version of this section // the fish version is notably simpler since - // - we can escape single quates within single quotes + // - we can escape single quotes within single quotes // - we don't have to deal with 'set -o nounset' return [ `set --global --append GHJK_CLEANUP_FISH 'test "$${key}" = \\'${safeVal}\\'; and '` + - `(if set -q ${key}; echo 'set --global --export ${key} \\'' "$${key}" "';"; else; echo 'set -e ${key};'; end;);`, + `(if set -q ${key}; echo 'set --global --export ${key} \\''"$${key}""';"; else; echo 'set -e ${key};'; end;);`, `set --global --export ${key} '${val}';`, ``, ]; @@ -358,8 +370,8 @@ async function writeActivators( }), ``, `# hooks that want to invoke ghjk are made to rely`, - `# on this shim to improving latency`, - ghjk_fish(gcx, denoDir, ghjkShimName), + `# on this shim to improve to improve reliablity`, + ghjk_fish(gcx, ghjkShimName), ``, `# only run the hooks in interactive mode`, `if status is-interactive;`, diff --git a/modules/mod.ts b/modules/mod.ts index daa35fa1..210079ab 100644 --- a/modules/mod.ts +++ b/modules/mod.ts @@ -1,29 +1,22 @@ -import { cliffy_cmd } from "../deps/cli.ts"; import { Blackboard } from "../host/types.ts"; +import { CliCommand } from "../src/deno_systems/types.ts"; import type { Json } from "../utils/mod.ts"; import type { GhjkCtx, ModuleManifest } from "./types.ts"; -export abstract class ModuleBase { +export abstract class ModuleBase { + constructor(protected gcx: GhjkCtx) {} /* init( _gcx: GhjkCtx, ): Promise | void {} */ - abstract processManifest( - gcx: GhjkCtx, + abstract loadConfig( manifest: ModuleManifest, bb: Blackboard, lockEnt: LockEnt | undefined, - ): Promise | Ctx; + ): Promise | void; // returns undefined if previous lock entry is no longer valid abstract loadLockEntry( - gcx: GhjkCtx, raw: Json, ): Promise | LockEnt | undefined; - abstract genLockEntry( - gcx: GhjkCtx, - mcx: Ctx, - ): Promise | Json; - abstract commands( - gcx: GhjkCtx, - mcx: Ctx, - ): Record>; + abstract genLockEntry(): Promise | Json; + abstract commands(): CliCommand[]; } diff --git a/modules/ports/ambient.ts b/modules/ports/ambient.ts index 6b290535..80031363 100644 --- a/modules/ports/ambient.ts +++ b/modules/ports/ambient.ts @@ -12,7 +12,7 @@ export class AmbientAccessPort extends PortBase { ); } } - async latestStable() { + override async latestStable() { const execPath = await this.pathToExec(); let versionOut; try { @@ -44,11 +44,11 @@ export class AmbientAccessPort extends PortBase { return [await this.latestStable()]; } - async listBinPaths(): Promise { + override async listBinPaths(): Promise { return [await this.pathToExec()]; } - async download() { + override async download() { // no op } diff --git a/modules/ports/ghrel.ts b/modules/ports/ghrel.ts index a15a6e55..6b7f27b6 100644 --- a/modules/ports/ghrel.ts +++ b/modules/ports/ghrel.ts @@ -50,7 +50,7 @@ export abstract class GithubReleasePort extends PortBase { return []; } - async download(args: DownloadArgs): Promise { + override async download(args: DownloadArgs): Promise { const urls = await this.downloadUrls(args); if (urls.length == 0) { throw new Error( @@ -65,7 +65,7 @@ export abstract class GithubReleasePort extends PortBase { ); } - async latestStable(args: ListAllArgs) { + override async latestStable(args: ListAllArgs) { const metadata = await $.withRetries({ count: 10, delay: $.exponentialBackoff(1000), diff --git a/modules/ports/mod.ts b/modules/ports/mod.ts index 382b82d4..98f9b7b2 100644 --- a/modules/ports/mod.ts +++ b/modules/ports/mod.ts @@ -1,6 +1,6 @@ export * from "./types.ts"; -import { cliffy_cmd, Table, zod } from "../../deps/cli.ts"; +import { Table, zod } from "../../deps/cli.ts"; import { $, Json, unwrapZodRes } from "../../utils/mod.ts"; import logger from "../../utils/logger.ts"; import validators, { @@ -35,6 +35,7 @@ import type { Provision, ProvisionReducer } from "../envs/types.ts"; import { getPortsCtx } from "./inter.ts"; import { updateInstall } from "./utils.ts"; import { getEnvsCtx } from "../envs/inter.ts"; +import { CliCommand } from "../../src/deno_systems/types.ts"; export type PortsCtx = { config: PortsModuleConfigX; @@ -49,9 +50,8 @@ const lockValidator = zod.object({ }); type PortsLockEnt = zod.infer; -export class PortsModule extends ModuleBase { - processManifest( - gcx: GhjkCtx, +export class PortsModule extends ModuleBase { + loadConfig( manifest: ModuleManifest, bb: Blackboard, _lockEnt: PortsLockEnt | undefined, @@ -67,7 +67,8 @@ export class PortsModule extends ModuleBase { validators.portsModuleConfigHashed.safeParse(manifest.config), ); - const pcx: PortsCtx = getPortsCtx(gcx); + const gcx = this.gcx; + const pcx = getPortsCtx(gcx); // pre-process the install sets found in the config for (const [id, hashedSet] of Object.entries(hashedModConf.sets)) { @@ -108,176 +109,70 @@ export class PortsModule extends ModuleBase { installSetProvisionTy, installSetReducer(gcx) as ProvisionReducer, ); - return pcx; } - commands( - gcx: GhjkCtx, - pcx: PortsCtx, - ) { - return { - ports: new cliffy_cmd.Command() - .alias("p") - .action(function () { - this.showHelp(); - }) - .description("Ports module, install programs into your env.") - .command( - "resolve", - new cliffy_cmd.Command() - .description(`Resolve all installs declared in config. - -- Useful to pre-resolve and add all install configs to the lockfile.`) - .action(async function () { - // scx contains a reference counted db connection - // somewhere deep in there - // so we need to use `using` - await using scx = await syncCtxFromGhjk(gcx); - for (const [_id, set] of Object.entries(pcx.config.sets)) { - void await buildInstallGraph(scx, set); - } - }), - ) - .command( - "outdated", - new cliffy_cmd.Command() - .description("Show a version table for installs") - .option( - "-u, --update-install ", - "Update specific install", - ) - .option("-n, --update-all", "Update all installs") - .action(async (opts) => { - const envsCtx = getEnvsCtx(gcx); - const envName = envsCtx.activeEnv; - - const installSets = pcx.config.sets; - - let currInstallSetId; - { - const activeEnvName = envsCtx.activeEnv; - const activeEnv = envsCtx.config - .envs[ - envsCtx.config.envsNamed[activeEnvName] ?? activeEnvName - ]; - if (!activeEnv) { - throw new Error( - `No env found under given name "${activeEnvName}"`, - ); - } - - const instSetRef = activeEnv.provides.filter((prov) => - prov.ty === installSetRefProvisionTy - )[0] as InstallSetRefProvision; - - currInstallSetId = instSetRef.setId; - } - const currInstallSet = installSets[currInstallSetId]; - const allowedDeps = currInstallSet.allowedBuildDeps; - - const rows = []; - const { - installedPortsVersions: installed, - latestPortsVersions: latest, - installConfigs, - } = await getOldNewVersionComparison( - gcx, - envName, - allowedDeps, - ); - for (let [installId, installedVersion] of installed.entries()) { - let latestVersion = latest.get(installId); - if (!latestVersion) { - throw new Error( - `Couldn't find the latest version for install id: ${installId}`, - ); - } - - if (latestVersion[0] === "v") { - latestVersion = latestVersion.slice(1); - } - if (installedVersion[0] === "v") { - installedVersion = installedVersion.slice(1); - } - - const config = installConfigs.get(installId); - - if (!config) { - throw new Error( - `Config not found for install id: ${installId}`, - ); - } - - if (config["specifiedVersion"]) { - latestVersion = "=" + latestVersion; - } - - const presentableConfig = { ...config }; - ["buildDepConfigs", "version", "specifiedVersion"].map( - (key) => { - delete presentableConfig[key]; - }, - ); - const row = [ - $.inspect(presentableConfig), - installedVersion, - latestVersion, - ]; - rows.push(row); - } - - if (opts.updateInstall) { - const installName = opts.updateInstall; - // TODO: convert from install name to install id, after port module refactor - let installId!: string; - const newVersion = latest.get(installId); - if (!newVersion) { - logger().info( - `Error while fetching the latest version for: ${installName}`, - ); - return; - } - await updateInstall(gcx, installId, newVersion, allowedDeps); - return; - } - - if (opts.updateAll) { - for (const [installId, newVersion] of latest.entries()) { - await updateInstall(gcx, installId, newVersion, allowedDeps); - } - return; - } - - const _versionTable = new Table() - .header(["Install Config", "Old Version", "New Version"]) - .body(rows) - .border() - .padding(1) - .indent(2) - .maxColWidth(30) - .render(); - }), - ) - .command( - "cleanup", - new cliffy_cmd.Command() - .description("TODO") - .action(function () { - throw new Error("TODO"); - }), - ), - }; + override commands() { + const gcx = this.gcx; + const pcx = getPortsCtx(gcx); + + const out: CliCommand[] = [{ + name: "ports", + visible_aliases: ["p"], + about: "Ports module, install programs into your env.", + sub_commands: [ + { + name: "resolve", + about: "Resolve all installs declared in config.", + before_long_help: + `- Useful to pre-resolve and add all install configs to the lockfile.`, + action: async function () { + // scx contains a reference counted db connection + // somewhere deep in there + // so we need to use `using` + await using scx = await syncCtxFromGhjk(gcx); + for (const [_id, set] of Object.entries(pcx.config.sets)) { + void await buildInstallGraph(scx, set); + } + }, + }, + { + name: "outdated", + about: "Show a version table for installs.", + flags: { + updateInstall: { + short: "u", + long: "update-install", + value_name: "INSTALL ID", + }, + updateAll: { + short: "a", + long: "update-all", + action: "SetTrue", + }, + }, + action: async function ( + { flags: { updateInstall, updateAll } }, + ) { + await outdatedCommand( + gcx, + pcx, + updateInstall as string | undefined, + updateAll as boolean | undefined, + ); + }, + }, + ], + }]; + return out; } - loadLockEntry( - gcx: GhjkCtx, - raw: Json, - ) { + + loadLockEntry(raw: Json) { const entry = lockValidator.parse(raw); if (entry.version != "0") { throw new Error(`unexepected version tag deserializing lockEntry`); } - const memoStore = getResolutionMemo(gcx); + const memoStore = getResolutionMemo(this.gcx); for (const [hash, config] of Object.entries(entry.configResolutions)) { logger().debug( "restoring resolution from lockfile", @@ -290,11 +185,8 @@ export class PortsModule extends ModuleBase { return entry; } - async genLockEntry( - gcx: GhjkCtx, - _pcx: PortsCtx, - ) { - const memo = getResolutionMemo(gcx); + async genLockEntry() { + const memo = getResolutionMemo(this.gcx); const configResolutions = Object.fromEntries( await Array.fromAsync( [...memo.entries()].map(async ([key, prom]) => [key, await prom]), @@ -307,6 +199,120 @@ export class PortsModule extends ModuleBase { } } +async function outdatedCommand( + gcx: GhjkCtx, + pcx: PortsCtx, + updateInstallFlag?: string, + updateAllFlag?: boolean, +) { + const envsCtx = getEnvsCtx(gcx); + const envName = envsCtx.activeEnv; + + const installSets = pcx.config.sets; + + let currInstallSetId; + { + const activeEnvName = envsCtx.activeEnv; + const activeEnv = envsCtx.config + .envs[ + envsCtx.config.envsNamed[activeEnvName] ?? activeEnvName + ]; + if (!activeEnv) { + throw new Error( + `No env found under given name "${activeEnvName}"`, + ); + } + + const instSetRef = activeEnv.provides.filter((prov) => + prov.ty === installSetRefProvisionTy + )[0] as InstallSetRefProvision; + + currInstallSetId = instSetRef.setId; + } + const currInstallSet = installSets[currInstallSetId]; + const allowedDeps = currInstallSet.allowedBuildDeps; + + const rows = []; + const { + installedPortsVersions: installed, + latestPortsVersions: latest, + installConfigs, + } = await getOldNewVersionComparison( + gcx, + envName, + allowedDeps, + ); + for (let [installId, installedVersion] of installed.entries()) { + let latestVersion = latest.get(installId); + if (!latestVersion) { + throw new Error( + `Couldn't find the latest version for install id: ${installId}`, + ); + } + + if (latestVersion[0] === "v") { + latestVersion = latestVersion.slice(1); + } + if (installedVersion[0] === "v") { + installedVersion = installedVersion.slice(1); + } + + const config = installConfigs.get(installId); + + if (!config) { + throw new Error( + `Config not found for install id: ${installId}`, + ); + } + + if (config["specifiedVersion"]) { + latestVersion = "=" + latestVersion; + } + + const presentableConfig = { ...config }; + ["buildDepConfigs", "version", "specifiedVersion"].map( + (key) => { + delete presentableConfig[key]; + }, + ); + const row = [ + $.inspect(presentableConfig), + installedVersion, + latestVersion, + ]; + rows.push(row); + } + + if (updateInstallFlag) { + const installId = updateInstallFlag; + const newVersion = latest.get(installId); + if (!newVersion) { + logger().info( + `Error while fetching the latest version for: ${installId}`, + ); + return; + } + await updateInstall(gcx, installId, newVersion, allowedDeps); + return; + } + + if (updateAllFlag) { + for (const [installId, newVersion] of latest.entries()) { + await updateInstall(gcx, installId, newVersion, allowedDeps); + } + return; + } + + const _versionTable = new Table() + .header(["Install Config", "Old Version", "New Version"]) + .body(rows) + .border() + .padding(1) + .indent(2) + .maxColWidth(30) + .render(); +} + async function getOldNewVersionComparison( gcx: GhjkCtx, envName: string, diff --git a/modules/ports/std.ts b/modules/ports/std.ts index a6388490..46dea825 100644 --- a/modules/ports/std.ts +++ b/modules/ports/std.ts @@ -1,5 +1,6 @@ //! This plugin exports the list of standard ports other -//! plugins are allowed to depend on. +//! plugins are expected to depend on. + import validators, { type AllowedPortDepX, type PortDep, @@ -12,7 +13,6 @@ import { manifest as man_git_aa } from "../../ports/git.ts"; import { manifest as man_curl_aa } from "../../ports/curl.ts"; import { manifest as man_cbin_ghrel } from "../../ports/cargo-binstall.ts"; import { manifest as man_node_org } from "../../ports/node.ts"; -import { manifest as man_pnpm_ghrel } from "../../ports/pnpm.ts"; import { manifest as man_asdf_plugin_git } from "../../ports/asdf_plugin_git.ts"; import { manifest as man_cpy_bs_ghrel } from "../../ports/cpy_bs.ts"; import { manifest as man_rustup_rustlang } from "../../ports/rustup.ts"; @@ -29,14 +29,12 @@ const aaPorts: PortManifest[] = [ const denoPorts: PortManifest[] = [ man_rustup_rustlang, - man_rust_rustup, man_cbin_ghrel, - man_pnpm_ghrel, - man_asdf_plugin_git, - // man_cpy_bs_ghrel, - // man_node_org, ]; +/** + * The default set of allowed port deps. + */ const defaultAllowedDeps: AllowedPortDepX[] = [ ...aaPorts, ...denoPorts, @@ -91,10 +89,6 @@ export const node_org = Object.freeze({ name: man_node_org.name, } as PortDep); -export const pnpm_ghrel = Object.freeze({ - name: man_pnpm_ghrel.name, -} as PortDep); - export const cpy_bs_ghrel = Object.freeze({ name: man_cpy_bs_ghrel.name, } as PortDep); diff --git a/modules/ports/std_runtime.ts b/modules/ports/std_runtime.ts new file mode 100644 index 00000000..58f0753a --- /dev/null +++ b/modules/ports/std_runtime.ts @@ -0,0 +1,17 @@ +//! The list of ports enabled when enableRuntimes is used on a ghjkfile configuration. + +import * as cpy_bs from "../../ports/cpy_bs.ts"; +import * as node from "../../ports/node.ts"; +import * as rust from "../../ports/rust.ts"; +import * as asdf_plugin_git from "../../ports/asdf_plugin_git.ts"; + +export default [ + // commonly used by the npmi port for installation using npm + node.default(), + // commonly used by the pipi port for installation using pip + cpy_bs.default(), + // commonly used by the cargobi port for building crates + rust.default(), + // used by the asdf port for installing asdf plugins + asdf_plugin_git.buildDep(), +]; diff --git a/modules/ports/sync.ts b/modules/ports/sync.ts index c39e6593..becd443c 100644 --- a/modules/ports/sync.ts +++ b/modules/ports/sync.ts @@ -53,7 +53,7 @@ export type SyncCtx = Awaited>; export async function syncCtxFromGhjk( gcx: GhjkCtx, ) { - const portsPath = await $.path(gcx.ghjkShareDir).resolve("ports") + const portsPath = await $.path(gcx.ghjkDataDir).resolve("ports") .ensureDir(); const [installsPath, downloadsPath, tmpPath] = ( await Promise.all([ @@ -518,9 +518,14 @@ function resolveConfig( version.match(new RegExp(`^v?${config.version}$`)) ); if (!match) { - throw new Error(`error resolving verison: not found`, { - cause: { config, manifest, allVersions }, - }); + throw new Error( + `error resolving verison ${config.version}: not found, available versions: [${ + allVersions.join(", ") + }]`, + { + cause: { config, manifest, allVersions }, + }, + ); } version = match; } else { diff --git a/modules/ports/worker.ts b/modules/ports/worker.ts index 5437aa74..97bf2d52 100644 --- a/modules/ports/worker.ts +++ b/modules/ports/worker.ts @@ -164,6 +164,9 @@ export class DenoWorkerPort extends PortBase { const worker = new Worker(import.meta.url, { name: `${this.manifest.name}@${this.manifest.version}`, type: "module", + // FIXME: catch worker errors or they bring down the whole + // program (no lockfile generated) + // TODO: proper permissions }); // promise that resolves when worker replies const promise = new Promise((resolve, reject) => { @@ -201,7 +204,7 @@ export class DenoWorkerPort extends PortBase { throw new Error(`unexpected response from worker ${JSON.stringify(res)}`); } - async latestStable(env: ListAllArgs) { + override async latestStable(env: ListAllArgs) { const req: WorkerReq = { ty: "latestStable", arg: env, @@ -214,7 +217,7 @@ export class DenoWorkerPort extends PortBase { throw new Error(`unexpected response from worker ${JSON.stringify(res)}`); } - async execEnv( + override async execEnv( args: ExecEnvArgs, ) { const req: WorkerReq = { @@ -228,7 +231,7 @@ export class DenoWorkerPort extends PortBase { } throw new Error(`unexpected response from worker ${JSON.stringify(res)}`); } - async listBinPaths( + override async listBinPaths( args: ListBinPathsArgs, ) { const req: WorkerReq = { @@ -243,7 +246,7 @@ export class DenoWorkerPort extends PortBase { throw new Error(`unexpected response from worker ${JSON.stringify(res)}`); } - async listLibPaths( + override async listLibPaths( args: ListBinPathsArgs, ) { const req: WorkerReq = { @@ -258,7 +261,7 @@ export class DenoWorkerPort extends PortBase { throw new Error(`unexpected response from worker ${JSON.stringify(res)}`); } - async listIncludePaths( + override async listIncludePaths( args: ListBinPathsArgs, ) { const req: WorkerReq = { @@ -273,7 +276,7 @@ export class DenoWorkerPort extends PortBase { throw new Error(`unexpected response from worker ${JSON.stringify(res)}`); } - async download(args: DownloadArgs) { + override async download(args: DownloadArgs) { const req: WorkerReq = { ty: "download", arg: args, @@ -285,7 +288,7 @@ export class DenoWorkerPort extends PortBase { } throw new Error(`unexpected response from worker ${JSON.stringify(res)}`); } - async install(args: InstallArgs) { + override async install(args: InstallArgs) { const req: WorkerReq = { ty: "install", arg: args, diff --git a/modules/tasks/mod.ts b/modules/tasks/mod.ts index 7c87f7ff..c5349c24 100644 --- a/modules/tasks/mod.ts +++ b/modules/tasks/mod.ts @@ -1,16 +1,17 @@ export * from "./types.ts"; -import { cliffy_cmd, zod } from "../../deps/cli.ts"; +import { zod } from "../../deps/cli.ts"; import { Json, unwrapZodRes } from "../../utils/mod.ts"; import validators from "./types.ts"; import type { TasksModuleConfigX } from "./types.ts"; -import { type GhjkCtx, type ModuleManifest } from "../types.ts"; +import { type ModuleManifest } from "../types.ts"; import { ModuleBase } from "../mod.ts"; import { buildTaskGraph, execTask, type TaskGraph } from "./exec.ts"; import { Blackboard } from "../../host/types.ts"; import { getTasksCtx } from "./inter.ts"; +import { CliCommand } from "../../src/deno_systems/types.ts"; export type TasksCtx = { config: TasksModuleConfigX; @@ -21,9 +22,8 @@ const lockValidator = zod.object({ }); type TasksLockEnt = zod.infer; -export class TasksModule extends ModuleBase { - processManifest( - gcx: GhjkCtx, +export class TasksModule extends ModuleBase { + loadConfig( manifest: ModuleManifest, bb: Blackboard, _lockEnt: TasksLockEnt | undefined, @@ -40,76 +40,69 @@ export class TasksModule extends ModuleBase { validators.tasksModuleConfig.safeParse(manifest.config), ); - const taskGraph = buildTaskGraph(gcx, config); + const taskGraph = buildTaskGraph(this.gcx, config); - const tasksCtx = getTasksCtx(gcx); - tasksCtx.config = config; - tasksCtx.taskGraph = taskGraph; - - return tasksCtx; + const tcx = getTasksCtx(this.gcx); + tcx.config = config; + tcx.taskGraph = taskGraph; } - commands( - gcx: GhjkCtx, - tcx: TasksCtx, - ) { + override commands() { + const gcx = this.gcx; + const tcx = getTasksCtx(this.gcx); + const namedSet = new Set(tcx.config.tasksNamed); - const commands = Object.keys(tcx.config.tasks) - .sort() - .map( - (key) => { - const def = tcx.config.tasks[key]; - const cmd = new cliffy_cmd.Command() - .name(key) - .useRawArgs() - .action(async (_, ...args) => { - await execTask( - gcx, - tcx.config, - tcx.taskGraph, - key, - args, - ); - }); - if (def.desc) { - cmd.description(def.desc); - } - if (!namedSet.has(key)) { - cmd.hidden(); - } - return cmd; - }, - ); - const root = new cliffy_cmd.Command() - .alias("x") - .action(function () { - this.showHelp(); - }) - .description("Tasks module."); - for (const cmd of commands) { - root.command(cmd.getName(), cmd); - } - return { - tasks: root, - }; + const out: CliCommand[] = [{ + name: "tasks", + visible_aliases: ["x"], + about: "Tasks module, execute your task programs.", + before_long_help: "The named tasks in your ghjkfile will be listed here.", + disable_help_subcommand: true, + sub_commands: [ + ...Object.keys(tcx.config.tasks) + .sort() + .map( + (key) => { + const def = tcx.config.tasks[key]; + return { + name: key, + about: def.desc, + hide: !namedSet.has(key), + args: { + raw: { + value_name: "TASK ARGS", + trailing_var_arg: true, + allow_hyphen_values: true, + action: "Append", + }, + }, + action: async ({ args: { raw } }) => { + await execTask( + gcx, + tcx.config, + tcx.taskGraph, + key, + (raw as string[]) ?? [], + ); + }, + } as CliCommand; + }, + ), + ], + }]; + return out; } - loadLockEntry( - _gcx: GhjkCtx, - raw: Json, - ) { + loadLockEntry(raw: Json) { const entry = lockValidator.parse(raw); if (entry.version != "0") { - throw new Error(`unexepected version tag deserializing lockEntry`); + throw new Error(`unexpected version tag deserializing lockEntry`); } return entry; } - genLockEntry( - _gcx: GhjkCtx, - _tcx: TasksCtx, - ) { + genLockEntry() { return { version: "0", }; diff --git a/modules/types.ts b/modules/types.ts index f1c23ced..561fa2b8 100644 --- a/modules/types.ts +++ b/modules/types.ts @@ -16,7 +16,7 @@ export type ModuleManifest = zod.infer; export type GhjkCtx = { ghjkfilePath?: Path; ghjkDir: Path; - ghjkShareDir: Path; + ghjkDataDir: Path; blackboard: Map; }; diff --git a/ports/act.ts b/ports/act.ts index 019f2362..9d947403 100644 --- a/ports/act.ts +++ b/ports/act.ts @@ -33,7 +33,7 @@ export class Port extends GithubReleasePort { repoOwner = "nektos"; repoName = "act"; - downloadUrls(args: DownloadArgs) { + override downloadUrls(args: DownloadArgs) { const { installVersion, platform } = args; let arch; switch (platform.arch) { @@ -73,7 +73,7 @@ export class Port extends GithubReleasePort { ].map(dwnUrlOut); } - async install(args: InstallArgs) { + override async install(args: InstallArgs) { const [{ name: fileName }] = this.downloadUrls(args); const fileDwnPath = std_path.resolve(args.downloadPath, fileName); diff --git a/ports/asdf.ts b/ports/asdf.ts index f32d8daf..dff7a474 100644 --- a/ports/asdf.ts +++ b/ports/asdf.ts @@ -72,7 +72,7 @@ export class Port extends PortBase { return out.split(/\s/).filter(Boolean).map((str) => str.trim()); } - async latestStable(args: ListAllArgs) { + override async latestStable(args: ListAllArgs) { const binPath = tryDepExecShimPath( std_ports.asdf_plugin_git, "latest-stable", @@ -93,7 +93,7 @@ export class Port extends PortBase { return out.trim(); } - async listBinPaths(args: ListBinPathsArgs) { + override async listBinPaths(args: ListBinPathsArgs) { const binPath = tryDepExecShimPath( std_ports.asdf_plugin_git, "list-bin-paths", @@ -113,7 +113,7 @@ export class Port extends PortBase { return out.split(/\s/).filter(Boolean).map((str) => str.trim()); } - async download(args: DownloadArgs) { + override async download(args: DownloadArgs) { // some plugins don't have a download script despite the spec const binPath = tryDepExecShimPath( std_ports.asdf_plugin_git, @@ -124,6 +124,7 @@ export class Port extends PortBase { return; } const conf = confValidator.parse(args.config); + await $.path(args.downloadPath).ensureDir(); await $`${binPath}` .env({ ...pathsWithDepArts(args.depArts, args.platform.os), @@ -134,8 +135,9 @@ export class Port extends PortBase { ASDF_DOWNLOAD_PATH: args.downloadPath, }); } - async install(args: InstallArgs) { + override async install(args: InstallArgs) { const conf = confValidator.parse(args.config); + await $.path(args.installPath).ensureDir(); await $`${ depExecShimPath(std_ports.asdf_plugin_git, "install", args.depArts) }` diff --git a/ports/asdf_plugin_git.ts b/ports/asdf_plugin_git.ts index 60bc7669..ab7c4458 100644 --- a/ports/asdf_plugin_git.ts +++ b/ports/asdf_plugin_git.ts @@ -1,8 +1,10 @@ import { $, + AllowedPortDep, defaultLatestStable, depExecShimPath, type DownloadArgs, + getPortRef, type InstallArgs, type InstallConfigSimple, type ListAllArgs, @@ -35,6 +37,13 @@ export type AsdfPluginInstallConf = & InstallConfigSimple & zod.input; +/** + * WARNING: this is probably no the function you want if you intend + * to add `asdf_plugin_git` to your `allowedBuildDeps`. + * + * This module exports a {@link buildDep} function for the purpose of adding + * the port to the allowedBuildDeps list. + */ export default function conf(config: AsdfPluginInstallConf) { return { ...confValidator.parse(config), @@ -42,6 +51,15 @@ export default function conf(config: AsdfPluginInstallConf) { }; } +export function buildDep(): AllowedPortDep { + return { + manifest, + defaultInst: { + portRef: getPortRef(manifest), + }, + }; +} + export class Port extends PortBase { async listAll(args: ListAllArgs) { const conf = confValidator.parse(args.config); @@ -55,11 +73,11 @@ export class Port extends PortBase { .map((line) => line.split(/\s/)[0].slice(0, 10)); } - latestStable(args: ListAllArgs): Promise { + override latestStable(args: ListAllArgs): Promise { return defaultLatestStable(this, args); } - async download(args: DownloadArgs) { + override async download(args: DownloadArgs) { if (await $.path(args.downloadPath).exists()) { // FIXME: remove this once download tracking is part of core return; @@ -74,7 +92,7 @@ export class Port extends PortBase { ); } - async install(args: InstallArgs) { + override async install(args: InstallArgs) { const tmpPath = $.path(args.tmpDirPath); // we copy the repo to a src dir const srcDir = (await tmpPath.ensureDir()).join("src"); diff --git a/ports/cargo-binstall.ts b/ports/cargo-binstall.ts index 9c594dca..ff8744bb 100644 --- a/ports/cargo-binstall.ts +++ b/ports/cargo-binstall.ts @@ -33,7 +33,7 @@ export class Port extends GithubReleasePort { repoOwner = "cargo-bins"; repoName = "cargo-binstall"; - downloadUrls( + override downloadUrls( args: DownloadArgs, ) { const { installVersion, platform } = args; @@ -68,7 +68,7 @@ export class Port extends GithubReleasePort { ].map(dwnUrlOut); } - async install(args: InstallArgs) { + override async install(args: InstallArgs) { const [{ name: fileName }] = this.downloadUrls(args); const fileDwnPath = std_path.resolve(args.downloadPath, fileName); diff --git a/ports/cargobi.ts b/ports/cargobi.ts index 845bb078..fb3d4683 100644 --- a/ports/cargobi.ts +++ b/ports/cargobi.ts @@ -101,11 +101,11 @@ export class Port extends PortBase { return versions.map((ver) => ver.vers); } - latestStable(args: ListAllArgs): Promise { + override latestStable(args: ListAllArgs): Promise { return defaultLatestStable(this, args); } - async download(args: DownloadArgs) { + override async download(args: DownloadArgs) { const conf = confValidator.parse(args.config); const fileName = conf.crateName; if (await std_fs.exists(std_path.resolve(args.downloadPath, fileName))) { @@ -181,7 +181,7 @@ export class Port extends PortBase { ); } - async install(args: InstallArgs) { + override async install(args: InstallArgs) { const installPath = $.path(args.installPath); if (await installPath.exists()) { await installPath.remove({ recursive: true }); diff --git a/ports/cmake.ts b/ports/cmake.ts deleted file mode 100644 index 99fcea11..00000000 --- a/ports/cmake.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { InstallConfigFat, InstallConfigSimple } from "../port.ts"; -import { AsdfInstallConf } from "./asdf.ts"; -import { PipiInstallConf } from "./pipi.ts"; -import * as ports from "./mod.ts"; - -/** - * Port to install cmake - * - * For macOS users, you need to add python as allowed build dependencies - * as cmake is downladed via pip install. - * - * Example: - * ```typescript - * const installs = { - python_latest: ports.cpy_bs({ version: "3.12.2", releaseTag: "20240224" }), -}; - * config({ - stdDeps: true, - allowedBuildDeps: [ - installs.python_latest - ], - enableRuntimes: true -}); - * ``` - * - */ -export default function conf( - config: InstallConfigSimple = {}, -): InstallConfigFat[] { - /* - The universal macOS cmake build downloaded by asdf crashes - due to security restrictions in macOS, so it's installed using pipi port instead, which runs with no problems. - */ - if (Deno.build.os === "darwin") { - const pipiConfig: PipiInstallConf = { - packageName: "cmake", - version: config.version, - }; - return ports.pipi(pipiConfig); - } - const asdfConfig: AsdfInstallConf = { - ...config, - pluginRepo: "https://github.com/asdf-community/asdf-cmake", - installType: "version", - version: config.version, - }; - - return [ports.asdf(asdfConfig)]; -} diff --git a/ports/cpy_bs.ts b/ports/cpy_bs.ts index 3c19603c..55150987 100644 --- a/ports/cpy_bs.ts +++ b/ports/cpy_bs.ts @@ -61,7 +61,7 @@ export default function conf( export class Port extends PortBase { repoOwner = "indygreg"; repoName = "python-build-standalone"; - execEnv( + override execEnv( args: PortArgsBase, ): Record | Promise> { return { @@ -71,7 +71,7 @@ export class Port extends PortBase { }; } - latestStable(args: ListAllArgs): Promise { + override latestStable(args: ListAllArgs): Promise { return defaultLatestStable(this, args); } @@ -136,7 +136,7 @@ export class Port extends PortBase { .sort((va, vb) => va.localeCompare(vb, undefined, { numeric: true })); } - async download(args: DownloadArgs) { + override async download(args: DownloadArgs) { const headers = ghHeaders(args.config); const conf = confValidator.parse(args.config); let tag = conf.releaseTag; @@ -176,7 +176,7 @@ export class Port extends PortBase { ); } - async install(args: InstallArgs) { + override async install(args: InstallArgs) { const [_, fileDwnEntry] = await Array.fromAsync( $.path(args.downloadPath).walk(), ); diff --git a/ports/deno_ghrel.ts b/ports/deno_ghrel.ts index 9da0d050..2a70df4d 100644 --- a/ports/deno_ghrel.ts +++ b/ports/deno_ghrel.ts @@ -35,7 +35,7 @@ export class Port extends GithubReleasePort { repoOwner = "denoland"; repoName = "deno"; - downloadUrls(args: DownloadArgs) { + override downloadUrls(args: DownloadArgs) { const { installVersion, platform } = args; const arch = platform.arch; let os; @@ -60,7 +60,7 @@ export class Port extends GithubReleasePort { ].map(dwnUrlOut); } - async install(args: InstallArgs) { + override async install(args: InstallArgs) { const [{ name: fileName }] = this.downloadUrls(args); const fileDwnPath = std_path.resolve(args.downloadPath, fileName); diff --git a/ports/dummy.ts b/ports/dummy.ts index 8ba1dfcd..8ea5c9cc 100644 --- a/ports/dummy.ts +++ b/ports/dummy.ts @@ -39,7 +39,7 @@ export default function conf(config: DummyInstallConf = {}) { } export class Port extends PortBase { - execEnv() { + override execEnv() { return { DUMMY_ENV: "dummy", }; @@ -49,7 +49,7 @@ export class Port extends PortBase { return ["dummy"]; } - async download(args: DownloadArgs) { + override async download(args: DownloadArgs) { const conf = confValidator.parse(args.config); // TODO: windows suport await $.path(args.downloadPath).join("bin", "dummy").writeText( @@ -61,7 +61,7 @@ echo ${conf.output ?? "dummy hey"}`, ); } - async install(args: InstallArgs) { + override async install(args: InstallArgs) { const installPath = $.path(args.installPath); await $.removeIfExists(installPath); await std_fs.copy(args.downloadPath, args.installPath); diff --git a/ports/earthly.ts b/ports/earthly.ts index fa41da87..b85c331b 100644 --- a/ports/earthly.ts +++ b/ports/earthly.ts @@ -31,7 +31,7 @@ export class Port extends GithubReleasePort { repoOwner = "earthly"; repoName = "earthly"; - downloadUrls(args: DownloadArgs) { + override downloadUrls(args: DownloadArgs) { const { installVersion, platform } = args; let arch; switch (platform.arch) { @@ -57,7 +57,7 @@ export class Port extends GithubReleasePort { ]; } - async install(args: InstallArgs) { + override async install(args: InstallArgs) { const installPath = $.path(args.installPath); if (await installPath.exists()) { await installPath.remove({ recursive: true }); diff --git a/ports/fx_ghrel.ts b/ports/fx_ghrel.ts new file mode 100644 index 00000000..c692000e --- /dev/null +++ b/ports/fx_ghrel.ts @@ -0,0 +1,72 @@ +import { + $, + DownloadArgs, + dwnUrlOut, + GithubReleasePort, + InstallArgs, + InstallConfigSimple, + osXarch, +} from "../port.ts"; +import { GithubReleasesInstConf, readGhVars } from "../modules/ports/ghrel.ts"; + +const manifest = { + ty: "denoWorker@v1" as const, + name: "fx_ghrel", + version: "0.1.0-alpha", + moduleSpecifier: import.meta.url, + platforms: osXarch(["linux", "windows", "darwin"], ["aarch64", "x86_64"]), +}; + +export default function conf( + config: InstallConfigSimple & GithubReleasesInstConf = {}, +) { + return { + ...readGhVars(), + ...config, + port: manifest, + }; +} + +export class Port extends GithubReleasePort { + repoOwner = "antonmedv"; + repoName = "fx"; + + override downloadUrls(args: DownloadArgs) { + const { installVersion, platform } = args; + let arch; + switch (platform.arch) { + case "x86_64": + arch = "amd64"; + break; + case "aarch64": + arch = "arm64"; + break; + default: + throw new Error(`unsupported: ${platform.arch}`); + } + const os = platform.os; + let ext; + switch (os) { + case "linux": + case "darwin": + ext = ""; + break; + case "windows": + ext = ".exe"; + break; + default: + throw new Error(`unsupported: ${platform.arch}`); + } + return [this.releaseArtifactUrl(installVersion, `fx_${os}_${arch}${ext}`)] + .map(dwnUrlOut) + .map((dwn) => ({ ...dwn, name: `fx${ext}`, mode: 0o700 })); + } + + override async install(args: InstallArgs) { + const installPath = $.path(args.installPath); + if (await installPath.exists()) { + await installPath.remove({ recursive: true }); + } + await $.path(args.downloadPath).copy(installPath.join("bin")); + } +} diff --git a/ports/infisical.ts b/ports/infisical.ts index 8667c83d..f44bda5f 100644 --- a/ports/infisical.ts +++ b/ports/infisical.ts @@ -39,16 +39,16 @@ export class Port extends GithubReleasePort { repoOwner = "Infisical"; repoName = "infisical"; - async listAll(args: ListAllArgs) { + override async listAll(args: ListAllArgs) { const all = await super.listAll(args); return all.map((str) => str.replace(/^infisical-cli\/v/, "")); } - async latestStable(args: ListAllArgs) { + override async latestStable(args: ListAllArgs) { const lsv = await super.latestStable(args); return lsv.replace(/^infisical-cli\/v/, ""); } - downloadUrls(args: DownloadArgs) { + override downloadUrls(args: DownloadArgs) { const { installVersion, platform } = args; let arch; switch (platform.arch) { @@ -84,7 +84,7 @@ export class Port extends GithubReleasePort { ].map(dwnUrlOut); } - async install(args: InstallArgs) { + override async install(args: InstallArgs) { const [{ name: fileName }] = this.downloadUrls(args); const fileDwnPath = std_path.resolve(args.downloadPath, fileName); diff --git a/ports/jq_ghrel.ts b/ports/jq_ghrel.ts index 27fa2674..e84fe915 100644 --- a/ports/jq_ghrel.ts +++ b/ports/jq_ghrel.ts @@ -38,7 +38,7 @@ export class Port extends GithubReleasePort { repoOwner = "jqlang"; repoName = "jq"; - downloadUrls(args: DownloadArgs) { + override downloadUrls(args: DownloadArgs) { const { installVersion, platform } = args; let arch; @@ -64,7 +64,7 @@ export class Port extends GithubReleasePort { .map((out) => ({ ...out, mode: 0o700 })); } - async install(args: InstallArgs) { + override async install(args: InstallArgs) { const installPath = $.path(args.installPath); await $.removeIfExists(installPath); diff --git a/ports/livekit_cli_ghrel.ts b/ports/livekit_cli_ghrel.ts new file mode 100644 index 00000000..04ed9f5e --- /dev/null +++ b/ports/livekit_cli_ghrel.ts @@ -0,0 +1,90 @@ +import { + $, + DownloadArgs, + dwnUrlOut, + GithubReleasePort, + InstallArgs, + InstallConfigSimple, + osXarch, + std_path, + unarchive, +} from "../port.ts"; +import { GithubReleasesInstConf, readGhVars } from "../modules/ports/ghrel.ts"; + +const manifest = { + ty: "denoWorker@v1" as const, + name: "livekit_cli_ghrel", + version: "0.1.0", + moduleSpecifier: import.meta.url, + // darwin releases only avail on brew + platforms: osXarch(["linux", "windows"], ["aarch64", "x86_64"]), +}; + +export default function conf( + config: InstallConfigSimple & GithubReleasesInstConf = {}, +) { + return { + ...readGhVars(), + ...config, + port: manifest, + }; +} + +export class Port extends GithubReleasePort { + repoOwner = "livekit"; + repoName = "livekit-cli"; + + override downloadUrls(args: DownloadArgs) { + const { installVersion, platform } = args; + let arch; + switch (platform.arch) { + case "x86_64": + arch = "amd64"; + break; + case "aarch64": + arch = "arm64"; + break; + default: + throw new Error(`unsupported: ${platform.arch}`); + } + const os = platform.os; + let ext; + switch (os) { + case "linux": + ext = "tar.gz"; + break; + case "windows": + ext = "zip"; + break; + default: + throw new Error(`unsupported: ${platform.arch}`); + } + return [ + this.releaseArtifactUrl( + installVersion, + `lk_${installVersion.replace(/^v/, "")}_${os}_${arch}.${ext}`, + ), + ].map(dwnUrlOut); + } + + override async install(args: InstallArgs) { + const [{ name: fileName }] = this.downloadUrls(args); + + const fileDwnPath = std_path.resolve(args.downloadPath, fileName); + await unarchive(fileDwnPath, args.tmpDirPath); + + const tmpDir = $.path(args.tmpDirPath); + const binDir = await tmpDir.join("bin").ensureDir(); + for (const fileName of ["lk"]) { + await tmpDir + .join(args.platform.os == "windows" ? fileName + ".exe" : fileName) + .renameToDir(binDir); + } + + const installPath = $.path(args.installPath); + if (await installPath.exists()) { + await installPath.remove({ recursive: true }); + } + await tmpDir.rename(installPath); + } +} diff --git a/ports/meta_cli_ghrel.ts b/ports/meta_cli_ghrel.ts index 97e6c696..3386852c 100644 --- a/ports/meta_cli_ghrel.ts +++ b/ports/meta_cli_ghrel.ts @@ -49,7 +49,7 @@ export class Port extends GithubReleasePort { repoOwner = "metatypedev"; repoName = "metatype"; - downloadUrls(args: DownloadArgs) { + override downloadUrls(args: DownloadArgs) { const conf = confValidator.parse(args.config); const { installVersion, platform } = args; let arch; @@ -88,7 +88,7 @@ export class Port extends GithubReleasePort { ].map(dwnUrlOut); } - async install(args: InstallArgs) { + override async install(args: InstallArgs) { const [{ name: fileName }] = this.downloadUrls(args); const fileDwnPath = std_path.resolve(args.downloadPath, fileName); diff --git a/ports/mod.ts b/ports/mod.ts index d2833cd6..b9782418 100644 --- a/ports/mod.ts +++ b/ports/mod.ts @@ -1,15 +1,17 @@ export { default as act } from "./act.ts"; export { default as asdf } from "./asdf.ts"; +export { default as asdf_plugin_git } from "./asdf_plugin_git.ts"; export { default as cargo_binstall } from "./cargo-binstall.ts"; export { default as cargobi } from "./cargobi.ts"; -export { default as cmake } from "./cmake.ts"; export { default as cpy_bs } from "./cpy_bs.ts"; export { default as curl } from "./curl.ts"; export { default as deno_ghrel } from "./deno_ghrel.ts"; export { default as earthly } from "./earthly.ts"; +export { default as fx_ghrel } from "./fx_ghrel.ts"; export { default as git } from "./git.ts"; export { default as infisical } from "./infisical.ts"; export { default as jq_ghrel } from "./jq_ghrel.ts"; +export { default as livekit_cli_ghrel } from "./livekit_cli_ghrel.ts"; export { default as meta_cli_ghrel } from "./meta_cli_ghrel.ts"; export { default as mold } from "./mold.ts"; export { default as node } from "./node.ts"; diff --git a/ports/mold.ts b/ports/mold.ts index 3d0f7ce9..345b1869 100644 --- a/ports/mold.ts +++ b/ports/mold.ts @@ -44,7 +44,7 @@ export class Port extends GithubReleasePort { repoOwner = "rui314"; repoName = "mold"; - downloadUrls(args: DownloadArgs) { + override downloadUrls(args: DownloadArgs) { const { installVersion, platform } = args; const os = platform.os; @@ -62,7 +62,7 @@ export class Port extends GithubReleasePort { ].map(dwnUrlOut); } - async install(args: InstallArgs) { + override async install(args: InstallArgs) { const [{ name: fileName }] = this.downloadUrls(args); const fileDwnPath = std_path.resolve(args.downloadPath, fileName); diff --git a/ports/node.ts b/ports/node.ts index 23405ab6..0cad73e9 100644 --- a/ports/node.ts +++ b/ports/node.ts @@ -44,19 +44,19 @@ export default function conf(config: InstallConfigSimple = {}) { } export class Port extends PortBase { - execEnv(args: ExecEnvArgs) { + override execEnv(args: ExecEnvArgs) { return { NODE_PATH: args.installPath, }; } - latestStable(args: ListAllArgs): Promise { + override latestStable(args: ListAllArgs): Promise { return defaultLatestStable(this, args); } // we wan't to avoid adding libraries found by default at /lib // to PATHs as they're just node_module sources - listLibPaths(): string[] { + override listLibPaths(): string[] { return []; } @@ -109,14 +109,14 @@ export class Port extends PortBase { ].map(dwnUrlOut); } - async download(args: DownloadArgs) { + override async download(args: DownloadArgs) { const urls = this.downloadUrls(args); await Promise.all( urls.map((obj) => downloadFile({ ...args, ...obj })), ); } - async install(args: InstallArgs) { + override async install(args: InstallArgs) { const [{ name: fileName }] = this.downloadUrls(args); const fileDwnPath = std_path.resolve(args.downloadPath, fileName); diff --git a/ports/npmi.ts b/ports/npmi.ts index b05ba128..22b6ccef 100644 --- a/ports/npmi.ts +++ b/ports/npmi.ts @@ -81,11 +81,11 @@ export class Port extends PortBase { return versions; } - async download(args: DownloadArgs) { + override async download(args: DownloadArgs) { const conf = confValidator.parse(args.config); await $.raw`${ depExecShimPath(std_ports.node_org, "npm", args.depArts) - } install --no-fund ${conf.packageName}@${args.installVersion}` + } install --prefix ${args.tmpDirPath} --no-fund ${conf.packageName}@${args.installVersion}` .cwd(args.tmpDirPath) .env(pathsWithDepArts(args.depArts, args.platform.os)); await std_fs.move(args.tmpDirPath, args.downloadPath); @@ -93,7 +93,7 @@ export class Port extends PortBase { // FIXME: replace shebangs with the runtime dep node path // default shebangs just use #!/bin/env node - async install(args: InstallArgs) { + override async install(args: InstallArgs) { const conf = confValidator.parse(args.config); await std_fs.copy( args.downloadPath, diff --git a/ports/opentofu_ghrel.ts b/ports/opentofu_ghrel.ts index 8cd9c5e6..98aebc4c 100644 --- a/ports/opentofu_ghrel.ts +++ b/ports/opentofu_ghrel.ts @@ -37,7 +37,7 @@ export class Port extends GithubReleasePort { repoOwner = "opentofu"; repoName = "opentofu"; - downloadUrls(args: DownloadArgs) { + override downloadUrls(args: DownloadArgs) { const { installVersion, platform } = args; let arch; @@ -65,7 +65,7 @@ export class Port extends GithubReleasePort { ].map(dwnUrlOut); } - async install(args: InstallArgs) { + override async install(args: InstallArgs) { const [{ name: fileName }] = this.downloadUrls(args); const fileDwnPath = std_path.resolve(args.downloadPath, fileName); diff --git a/ports/pipi.ts b/ports/pipi.ts index 72992799..7669f274 100644 --- a/ports/pipi.ts +++ b/ports/pipi.ts @@ -62,12 +62,12 @@ export class Port extends PortBase { return metadata.versions; } - latestStable(args: ListAllArgs): Promise { + override latestStable(args: ListAllArgs): Promise { return defaultLatestStable(this, args); } // this creates the venv and install the package into it - async download(args: DownloadArgs) { + override async download(args: DownloadArgs) { const downloadPath = $.path(args.downloadPath); if (await downloadPath.exists()) { return; @@ -142,7 +142,7 @@ export class Port extends PortBase { // this modifies the venv so that it works with ghjk // and exposes the packages and only the package's console scripts - async install(args: InstallArgs) { + override async install(args: InstallArgs) { const tmpPath = $.path(args.tmpDirPath); const conf = confValidator.parse(args.config); @@ -202,7 +202,7 @@ export class Port extends PortBase { .map((execPath) => Deno.symlink( // create a relative symlink - // TODO: open ticket on dsherret/tax about createSymlinkTo(relative) bug + // TODO: open ticket on dsherret/jax about createSymlinkTo(relative) bug ".." + execPath.slice(tmpPath.toString().length), tmpPath .join("bin", $.path(execPath).basename()).toString(), diff --git a/ports/pnpm.ts b/ports/pnpm.ts index 353c661e..24a83e35 100644 --- a/ports/pnpm.ts +++ b/ports/pnpm.ts @@ -31,7 +31,7 @@ export class Port extends GithubReleasePort { repoOwner = "pnpm"; repoName = "pnpm"; - downloadUrls(args: DownloadArgs) { + override downloadUrls(args: DownloadArgs) { const { installVersion, platform } = args; let arch; let os; @@ -74,7 +74,7 @@ export class Port extends GithubReleasePort { ]; } - async install(args: InstallArgs) { + override async install(args: InstallArgs) { const [{ name: fileName }] = this.downloadUrls(args); const installPath = $.path(args.installPath); diff --git a/ports/poetry.ts b/ports/poetry.ts index 9b68ae70..653605cd 100644 --- a/ports/poetry.ts +++ b/ports/poetry.ts @@ -49,22 +49,22 @@ const toPipiConfig = (config: InstallConfigLiteX) => ({ }); export class Port extends PipiPort { - listAll(args: ListAllArgs) { + override listAll(args: ListAllArgs) { return super.listAll({ ...args, config: toPipiConfig(args.config) }); } - latestStable(args: ListAllArgs): Promise { + override latestStable(args: ListAllArgs): Promise { return defaultLatestStable(this, { ...args, config: toPipiConfig(args.config), }); } - download(args: DownloadArgs) { + override download(args: DownloadArgs) { return super.download({ ...args, config: toPipiConfig(args.config) }); } - install(args: InstallArgs) { + override install(args: InstallArgs) { return super.install({ ...args, config: toPipiConfig(args.config) }); } } diff --git a/ports/protoc.ts b/ports/protoc.ts index 67b28ac4..e6ea1729 100644 --- a/ports/protoc.ts +++ b/ports/protoc.ts @@ -33,7 +33,7 @@ export class Port extends GithubReleasePort { repoOwner = "protocolbuffers"; repoName = "protobuf"; - downloadUrls(args: DownloadArgs) { + override downloadUrls(args: DownloadArgs) { const { installVersion, platform } = args; let os; switch (platform.os) { @@ -66,7 +66,7 @@ export class Port extends GithubReleasePort { ].map(dwnUrlOut); } - async install(args: InstallArgs) { + override async install(args: InstallArgs) { const [{ name: fileName }] = this.downloadUrls(args); const fileDwnPath = $.path(args.downloadPath).join(fileName); diff --git a/ports/ruff.ts b/ports/ruff.ts index 87aa0c7f..fa1d75d2 100644 --- a/ports/ruff.ts +++ b/ports/ruff.ts @@ -41,7 +41,7 @@ export class Port extends GithubReleasePort { repoOwner = "astral-sh"; repoName = "ruff"; - downloadUrls(args: DownloadArgs) { + override downloadUrls(args: DownloadArgs) { const { installVersion, platform } = args; let arch; switch (platform.arch) { @@ -89,7 +89,7 @@ export class Port extends GithubReleasePort { ].map(dwnUrlOut); } - async install(args: InstallArgs) { + override async install(args: InstallArgs) { const [{ name: fileName }] = this.downloadUrls(args); const fileDwnPath = std_path.resolve(args.downloadPath, fileName); diff --git a/ports/rust.ts b/ports/rust.ts index 2819f8bf..5d34b6dd 100644 --- a/ports/rust.ts +++ b/ports/rust.ts @@ -128,13 +128,13 @@ export class Port extends PortBase { return versions; } - async latestStable(args: ListAllArgs) { + override async latestStable(args: ListAllArgs) { const versions = await this.listAll(args); // stable releases are just version numbers, no return versions.findLast((ver) => !ver.match(/[a-zA-Z]/))!; } - async download(args: DownloadArgs) { + override async download(args: DownloadArgs) { const conf = confValidator.parse(args.config); const tmpPath = $.path(args.tmpDirPath); @@ -159,7 +159,7 @@ export class Port extends PortBase { ); } - async install(args: InstallArgs) { + override async install(args: InstallArgs) { const installPath = $.path(args.installPath); if (await installPath.exists()) { await installPath.remove({ recursive: true }); diff --git a/ports/rustup.ts b/ports/rustup.ts index 3ab972e7..0044790b 100644 --- a/ports/rustup.ts +++ b/ports/rustup.ts @@ -60,7 +60,7 @@ export class Port extends PortBase { .sort((a, b) => a.localeCompare(b, undefined, { numeric: true })); } - latestStable(args: ListAllArgs): Promise { + override latestStable(args: ListAllArgs): Promise { return defaultLatestStable(this, args); } @@ -99,14 +99,14 @@ export class Port extends PortBase { ].map(dwnUrlOut); } - async download(args: DownloadArgs) { + override async download(args: DownloadArgs) { const urls = this.downloadUrls(args); await Promise.all( urls.map((obj) => downloadFile({ ...args, ...obj, mode: 0o700 })), ); } - async install(args: InstallArgs) { + override async install(args: InstallArgs) { const installPath = $.path(args.installPath); if (await installPath.exists()) { await installPath.remove({ recursive: true }); diff --git a/ports/temporal_cli.ts b/ports/temporal_cli.ts index 132f2d6a..d8a7c611 100644 --- a/ports/temporal_cli.ts +++ b/ports/temporal_cli.ts @@ -33,7 +33,7 @@ export class Port extends GithubReleasePort { repoOwner = "temporalio"; repoName = "cli"; - downloadUrls(args: DownloadArgs) { + override downloadUrls(args: DownloadArgs) { const { installVersion, platform } = args; let arch; switch (platform.arch) { @@ -55,7 +55,7 @@ export class Port extends GithubReleasePort { ].map(dwnUrlOut); } - async install(args: InstallArgs) { + override async install(args: InstallArgs) { const [{ name: fileName }] = this.downloadUrls(args); const fileDwnPath = std_path.resolve(args.downloadPath, fileName); diff --git a/ports/terraform.ts b/ports/terraform.ts index f811d5a2..4c88bf75 100644 --- a/ports/terraform.ts +++ b/ports/terraform.ts @@ -41,7 +41,7 @@ export class Port extends PortBase { return versions.reverse(); } - async latestStable() { + override async latestStable() { const all = await this.listAll(); // stable versions don't have any additional info in theform of 1.2.3-alpha return all.findLast((str) => !str.match(/-/))!; @@ -68,14 +68,14 @@ export class Port extends PortBase { ].map(dwnUrlOut); } - async download(args: DownloadArgs) { + override async download(args: DownloadArgs) { const urls = this.downloadUrls(args); await Promise.all( urls.map((obj) => downloadFile({ ...args, ...obj })), ); } - async install(args: InstallArgs) { + override async install(args: InstallArgs) { const [{ name: fileName }] = this.downloadUrls(args); const fileDwnPath = std_path.resolve(args.downloadPath, fileName); diff --git a/ports/wasmedge.ts b/ports/wasmedge.ts index be3f915b..b35175ec 100644 --- a/ports/wasmedge.ts +++ b/ports/wasmedge.ts @@ -63,7 +63,7 @@ export class Port extends GithubReleasePort { repoOwner = "WasmEdge"; repoName = "WasmEdge"; - execEnv(args: ExecEnvArgs) { + override execEnv(args: ExecEnvArgs) { return { WASMEDGE_DIR: args.installPath, // WASMEDGE_LIB_DIR: std_path.resolve(args.installPath, "lib64"), @@ -71,11 +71,11 @@ export class Port extends GithubReleasePort { }; } - listLibPaths(): string[] { + override listLibPaths(): string[] { return ["lib*/*"]; } - downloadUrls(args: DownloadArgs) { + override downloadUrls(args: DownloadArgs) { const { installVersion, platform } = args; let fileName; if (platform.os == "darwin") { @@ -120,7 +120,7 @@ export class Port extends GithubReleasePort { ].map(dwnUrlOut); } - async install(args: InstallArgs) { + override async install(args: InstallArgs) { const [{ name: fileName }] = this.downloadUrls(args); const fileDwnPath = std_path.resolve(args.downloadPath, fileName); diff --git a/ports/zstd.ts b/ports/zstd.ts index 3f792cfd..3e6261df 100644 --- a/ports/zstd.ts +++ b/ports/zstd.ts @@ -10,7 +10,7 @@ export const manifest: AmbientAccessPortManifest = { version: "0.1.0", execName: "zstd", versionExtractFlag: "--version", - versionExtractRegex: "v(\\d+\\.\\d+\\.\\d+),", + versionExtractRegex: "v(\\d+\\.\\d+\\.\\d+)", versionExtractRegexFlags: "", platforms: osXarch(["linux", "darwin"], ["aarch64", "x86_64"]), }; diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 00000000..762d4cf1 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,6 @@ +[toolchain] +# NOTE: to change this, change the const RUST_VERSION in ghjk.ts and +# then use the lock-sed task +channel = "1.82.0" +components = ["rustfmt", "clippy"] +targets = ["wasm32-unknown-unknown", "wasm32-wasi"] diff --git a/scripts/check.ts b/scripts/check.ts deleted file mode 100755 index dcc56fea..00000000 --- a/scripts/check.ts +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/env -S ghjk deno run --allow-env --allow-run --allow-read --allow-write=. - -import "../setup_logger.ts"; -import { $ } from "../utils/mod.ts"; - -const files = (await Array.fromAsync( - $.path(import.meta.url).parentOrThrow().expandGlob("**/*.ts", { - exclude: [ - ".git", - ".dev", - "play.ts", - ".ghjk/**", - ".deno-dir/**", - "vendor/**", - ".git/**", // was throwing an error without this - ], - }), -)).map((ref) => ref.path.toString()); - -await $`${Deno.env.get("DENO_EXEC_PATH") ?? "deno"} check ${files}`; diff --git a/scripts/dev.ts b/scripts/dev.ts deleted file mode 100755 index 61a94af1..00000000 --- a/scripts/dev.ts +++ /dev/null @@ -1,67 +0,0 @@ -#!/bin/env -S deno run -A - -//! Spawns the provided arguments within an environment -//! that contains a ghjk installation from the repo instead -//! of the gloabl ghjk installation - -import { defaultInstallArgs, install } from "../install/mod.ts"; -import { $ } from "../utils/mod.ts"; - -const devDir = $.path( - import.meta.dirname!, - // await Deno.makeTempDir({ - // prefix: "ghjk_le2e_", - // }), -).join("../.dev"); - -const ghjkShareDir = await devDir.join("ghjk").ensureDir(); - -await (await $.removeIfExists(devDir.join("ghjk.ts"))) - .symlinkTo(import.meta.resolve("../ghjk.ts")); - -const env: Record = { - BASH_ENV: `${ghjkShareDir.toString()}/env.bash`, - ZDOTDIR: ghjkShareDir.toString(), - GHJK_SHARE_DIR: ghjkShareDir.toString(), - PATH: `${ghjkShareDir.toString()}:${Deno.env.get("PATH")}`, - HOME: devDir.toString(), -}; - -{ - const confHome = await ghjkShareDir.join(".config").ensureDir(); - const fishConfDir = await confHome.join("fish").ensureDir(); - await (await $.removeIfExists(fishConfDir.join("config.fish"))) - .symlinkTo(ghjkShareDir.join("env.fish").toString()); - env["XDG_CONFIG_HOME"] = confHome.toString(); -} - -// install ghjk -await install({ - ...defaultInstallArgs, - skipExecInstall: false, - ghjkExecInstallDir: ghjkShareDir.toString(), - // share the system's deno cache - ghjkDenoCacheDir: Deno.env.get("DENO_DIR") ?? - $.path(Deno.env.get("HOME")!).join(".cache", "deno").toString(), - ghjkShareDir: ghjkShareDir.toString(), - // don't modify system shell configs - shellsToHook: [], -}); - -// await $`${ghjkShareDir.join("ghjk").toString()} print config` -// .cwd(devDir.toString()) -// .clearEnv() -// .env(env); -// -// await $`${ghjkShareDir.join("ghjk").toString()} envs cook` -// .cwd(devDir.toString()) -// .clearEnv() -// .env(env); -let cmd; -if (Deno.args.length == 1 && Deno.args[0] == "bash") { - cmd = $`bash --rcfile ${env.BASH_ENV}`; -} else { - cmd = $`${Deno.args}`; -} -await cmd.env(env).noThrow() - .cwd(Deno.env.get("CWD") ?? Deno.cwd()); diff --git a/src/deno_systems/bindings.ts b/src/deno_systems/bindings.ts new file mode 100644 index 00000000..d1f58b70 --- /dev/null +++ b/src/deno_systems/bindings.ts @@ -0,0 +1,176 @@ +// NOTE: this mechanism is currently offline for deno systems +// we just +// +// we catch all rejections and explicityly dispatch them to the host +// to avoid shutting down the event loop on uncaught errors +globalThis.addEventListener("unhandledrejection", (evt) => { + let reason = evt.reason; + if (reason instanceof Error) { + reason = reason.stack; + } + if (Ghjk.dispatchException(reason)) { + evt.preventDefault(); + } +}); + +// start an interval to prevent the event loop exiting +// after loading systems +setInterval(() => {/* beat */}, 1000); + +// import "../../src/ghjk/js/mock.sfx.ts"; +import { zod } from "../../deps/common.ts"; +import { $, unwrapZodRes } from "../../utils/mod.ts"; +import type { GhjkCtx, ModuleManifest } from "../../modules/types.ts"; +import type { ModuleBase } from "../../modules/mod.ts"; +import type { Blackboard } from "../../host/types.ts"; +import { Ghjk, Json } from "../ghjk/js/runtime.js"; + +import type { + CliCommand, + CliCommandBindedX, + DenoSystemsRoot, +} from "./types.ts"; +import bindingTypes from "./types.ts"; + +// FIXME: better means of exit detection, keep alive as long +// as callbacks are registered? +// globalThis.onbeforeunload = (evt) => { +// evt.preventDefault(); +// }; + +const prepareArgs = zod.object({ + uri: zod.string(), + config: zod.object({ + ghjkfile: zod.string().optional(), + ghjkdir: zod.string(), + data_dir: zod.string(), + deno_lockfile: zod.string().optional(), + repo_root: zod.string(), + deno_dir: zod.string(), + }), +}); + +const args = prepareArgs.parse(Ghjk.blackboard.get("args")); +await prepareSystems(args); + +async function prepareSystems(args: zod.infer) { + const gcx = { + ghjkDir: $.path(args.config.ghjkdir), + ghjkDataDir: $.path(args.config.data_dir), + ghjkfilePath: args.config.ghjkfile + ? $.path(args.config.ghjkfile) + : undefined, + blackboard: new Map(), + } satisfies GhjkCtx; + + const { default: mod } = await import(args.uri); + const { systems } = unwrapZodRes( + bindingTypes.denoSystemsRoot.safeParse(mod), + ) as DenoSystemsRoot; + + const manifests = [] as ManifestDesc[]; + + for (const [id, ctorFn] of Object.entries(systems)) { + manifests.push({ + id, + ctor_cb_key: Ghjk.callbacks.set( + `sys_ctor_${id}_${crypto.randomUUID()}`, + () => { + const instance = ctorFn(gcx); + return instanceBinding(gcx, id, instance); + }, + ), + }); + } + await Ghjk.hostcall("register_systems", manifests); +} + +type ManifestDesc = { + id: string; + ctor_cb_key: string; +}; + +type InstanceDesc = { + load_lock_entry_cb_key: string; + gen_lock_entry_cb_key: string; + load_config_cb_key: string; + cli_commands_cb_key: string; +}; + +function instanceBinding( + gcx: GhjkCtx, + sys_id: string, + instance: ModuleBase, +) { + const instanceId = crypto.randomUUID(); + type State = { + stateKey: string; + }; + return { + load_config_cb_key: Ghjk.callbacks.set( + `sys_load_config_${instanceId}`, + async (args: Json) => { + const { config, bb, state: stateRaw } = args as { + config: ModuleManifest; + bb: Blackboard; + state?: State; + }; + const state = stateRaw?.stateKey + ? gcx.blackboard.get(stateRaw?.stateKey) + : undefined; + await instance.loadConfig({ id: sys_id, config }, bb, state); + return null; + }, + ), + load_lock_entry_cb_key: Ghjk.callbacks.set( + `sys_load_lock_entry_${instanceId}`, + async (args: Json) => { + const { raw } = args as any; + const state = await instance.loadLockEntry(raw); + const stateKey = `sys_state_${instanceId}`; + gcx.blackboard.set(stateKey, state); + return { + stateKey, + } satisfies State; + }, + ), + gen_lock_entry_cb_key: Ghjk.callbacks.set( + `sys_gen_lock_entry_${instanceId}`, + () => { + return instance.genLockEntry(); + }, + ), + cli_commands_cb_key: Ghjk.callbacks.set( + `sys_cli_commands_${instanceId}`, + (_) => { + const commandsRaw = instance.commands(); + return commandsRaw.map((cmd) => + commandBinding(cmd) as CliCommandBindedX + ); + }, + ), + } satisfies InstanceDesc; +} + +function commandBinding(commandRaw: CliCommand): CliCommandBindedX { + const { action, sub_commands, ...command } = bindingTypes.cliCommand.parse( + commandRaw, + ); + const actionId = crypto.randomUUID(); + return { + ...command, + sub_commands: sub_commands + ? sub_commands.map((cmd) => commandBinding(cmd)) + : undefined, + action_cb_key: action + ? Ghjk.callbacks.set( + `sys_cli_command_action_${command.name}_${actionId}`, + async (args) => { + const actionArgs = bindingTypes.cliActionArgs.parse(args); + await action(actionArgs); + return {}; + }, + ) + : undefined, + } satisfies CliCommandBindedX; +} diff --git a/src/deno_systems/mod.ts b/src/deno_systems/mod.ts new file mode 100644 index 00000000..92e45319 --- /dev/null +++ b/src/deno_systems/mod.ts @@ -0,0 +1,10 @@ +import { map } from "../../modules/std.ts"; +import type { DenoSystemsRoot } from "./types.ts"; + +export default { + systems: Object.fromEntries( + Object.entries(map).map( + ([id, sys]) => [id, (gcx) => new sys.ctor(gcx)], + ), + ), +} satisfies DenoSystemsRoot; diff --git a/src/deno_systems/types.ts b/src/deno_systems/types.ts new file mode 100644 index 00000000..85b0e178 --- /dev/null +++ b/src/deno_systems/types.ts @@ -0,0 +1,145 @@ +import { zod } from "../../deps/common.ts"; +import type { GhjkCtx } from "../../modules/types.ts"; +import type { ModuleBase } from "../../modules/mod.ts"; + +const denoSystemsRoot = zod.object({ + systems: zod.record(zod.function()), +}); + +const charSchema = zod.string().length(1); + +const cliArg = zod.object({ + value_name: zod.string().optional(), + value_hint: zod.enum([ + "Unknown", + "Other", + "AnyPath", + "FilePath", + "DirPath", + "ExecutablePath", + "CommandName", + "CommandString", + // "CommandWithArguments", + "Username", + "Hostname", + "Url", + "EmailAddress", + ]).optional(), + + action: zod.enum([ + "Set", + "Append", + "SetTrue", + "SetFalse", + "Count", + "Help", + "HelpShort", + "HelpLong", + "Version", + ]).optional(), + + required: zod.boolean().optional(), + global: zod.boolean().optional(), + hide: zod.boolean().optional(), + exclusive: zod.boolean().optional(), + trailing_var_arg: zod.boolean().optional(), + + env: zod.string().optional(), + + help: zod.string().optional(), + long_help: zod.string().optional(), +}); + +const cliFlag = cliArg.extend({ + long: zod.string().optional(), + long_aliases: zod.string().array().optional(), + visible_long_aliases: zod.string().array().optional(), + + short: charSchema.optional(), + short_aliases: charSchema.array().optional(), + visible_short_aliases: charSchema.array().optional(), +}); + +const cliCommandBase = zod.object({ + name: zod.string(), + + aliases: zod.string().array().optional(), + visible_aliases: zod.string().array().optional(), + + hide: zod.boolean().optional(), + disable_help_subcommand: zod.boolean().optional(), + + about: zod.string().optional(), + before_help: zod.string().optional(), + before_long_help: zod.string().optional(), + + args: zod.record(cliArg).optional(), + flags: zod.record(cliFlag).optional(), +}); + +const flagsAndArgs = zod.record( + zod.union([ + zod.string(), + zod.string().array(), + zod.number(), + zod.boolean(), + ]).optional(), +); + +const cliActionArgs = zod.object({ + flags: flagsAndArgs, + args: flagsAndArgs, +}); + +const cliCommandActionBase = cliCommandBase.extend({ + action: zod.function() + .args(cliActionArgs) + .returns(zod.union([zod.promise(zod.void()), zod.void()])).optional(), +}); + +const cliCommandBindedBase = cliCommandBase.extend({ + action_cb_key: zod.string().optional(), +}); + +const cliCommand: zod.ZodType = cliCommandActionBase.extend({ + sub_commands: zod.lazy(() => zod.array(cliCommand).optional()), +}); + +const cliCommandBinded: zod.ZodType = cliCommandBindedBase + .extend({ + sub_commands: zod.lazy(() => zod.array(cliCommandBinded).optional()), + }); + +type DenoSystemCtor = (gcx: GhjkCtx) => ModuleBase; + +export type DenoSystemsRoot = { + systems: Record; +}; + +export type CliCommand = zod.input & { + sub_commands?: CliCommand[]; +}; +export type CliCommandX = zod.infer & { + sub_commands?: CliCommandX[]; +}; + +export type CliCommandBinded = zod.input & { + sub_commands?: CliCommandBinded[]; +}; +export type CliCommandBindedX = zod.infer & { + sub_commands?: CliCommandBindedX[]; +}; + +export type CliFlag = zod.input; +export type CliFlagX = zod.infer; + +export type CliArg = zod.input; +export type CliArgX = zod.infer; + +export default { + denoSystemsRoot, + cliFlag, + cliArg, + cliCommand, + cliActionArgs, +}; diff --git a/src/denort/Cargo.toml b/src/denort/Cargo.toml new file mode 100644 index 00000000..54c4a0cd --- /dev/null +++ b/src/denort/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "denort" +version.workspace = true +edition.workspace = true + +[lib] +path = "lib.rs" + +[dependencies] +tracing-unwrap.workspace = true + +educe.workspace = true + +color-eyre.workspace = true +anyhow.workspace = true + +tracing.workspace = true +tracing-subscriber.workspace = true + +deno.workspace = true + +tokio.workspace = true diff --git a/src/denort/lib.rs b/src/denort/lib.rs new file mode 100644 index 00000000..3706ef1f --- /dev/null +++ b/src/denort/lib.rs @@ -0,0 +1,327 @@ +#![allow(clippy::let_and_return)] + +pub use deno; + +pub mod macros; +pub mod promises; +pub mod unsync; +pub mod worker; + +#[allow(unused)] +mod interlude { + pub use std::future::Future; + pub use std::path::{Path, PathBuf}; + pub use std::sync::Arc; + + pub use color_eyre::eyre; + pub use deno::deno_runtime::{ + self, + deno_core::{self, v8}, + }; + pub use eyre::{format_err as ferr, Context, Result as Res, WrapErr}; + pub use tracing::{debug, error, info, trace, warn, Instrument}; + pub use tracing_unwrap::*; +} +use crate::interlude::*; + +use deno::deno_runtime::{ + deno_core::{futures::FutureExt, unsync::JoinHandle, ModuleSpecifier}, + deno_permissions, + tokio_util::create_and_run_current_thread_with_maybe_metrics, +}; + +#[rustfmt::skip] +use deno_runtime::deno_core as deno_core; // necessary for re-exported macros to work + +const DEFAULT_UNSTABLE_FLAGS: &[&str] = &["worker-options", "kv" /* "net", "http" */]; + +/// This must be called on the main thread as early as possible +/// or one will encounter stack overflows and segmentation faults +pub fn init() { + deno::util::v8::init_v8_flags(&[], &[], deno::util::v8::get_v8_flags_from_env()); + // The stack will blow on debug builds unless we increase the size + if cfg!(debug_assertions) { + // We must do this early before any new threads are started + // since std::thread might cache RUST_MIN_STACK once it's read this env + if std::env::var("RUST_MIN_STACK").is_err() { + std::env::set_var("RUST_MIN_STACK", "8388608"); + } + }; +} + +/// Ensure that the subcommand runs in a task, rather than being directly executed. Since some of these +/// futures are very large, this prevents the stack from getting blown out from passing them by value up +/// the callchain (especially in debug mode when Rust doesn't have a chance to elide copies!). +#[inline(always)] +fn spawn_subcommand + 'static>(f: F) -> JoinHandle<()> { + // the boxed_local() is important in order to get windows to not blow the stack in debug + deno_core::unsync::spawn(f.boxed_local()) +} +pub fn run_sync( + main_mod: ModuleSpecifier, + config_file: Option, + permissions: deno::args::PermissionFlags, + custom_extensions: Arc, +) { + new_thread_builder() + .spawn(|| { + create_and_run_current_thread_with_maybe_metrics(async move { + spawn_subcommand(async move { + run(main_mod, config_file, permissions, custom_extensions) + .await + .unwrap() + }) + .await + .unwrap() + }) + }) + .unwrap() + .join() + .unwrap(); +} + +pub async fn run( + main_module: ModuleSpecifier, + config_file: Option, + permissions: deno::args::PermissionFlags, + custom_extensions: Arc, +) -> anyhow::Result<()> { + // NOTE: avoid using the Run subcommand + // as it breaks our custom_extensions patch for some reason + let flags = deno::args::Flags { + permissions, + unstable_config: deno::args::UnstableConfig { + features: DEFAULT_UNSTABLE_FLAGS + .iter() + .copied() + .map(String::from) + .collect(), + ..Default::default() + }, + config_flag: if let Some(config_file) = config_file { + deno::args::ConfigFlag::Path(config_file) + } else { + Default::default() + }, + ..Default::default() + }; + + let flags = Arc::new(flags); + + let cli_factory = + deno::factory::CliFactory::from_flags(flags).with_custom_ext_cb(custom_extensions); + + let worker_factory = cli_factory.create_cli_main_worker_factory().await?; + + let mut worker = worker_factory + .create_main_worker(deno_runtime::WorkerExecutionMode::Run, main_module) + .await?; + tracing::info!("running worker"); + let exit_code = worker.run().await?; + println!("exit_code: {exit_code}"); + + Ok(()) +} + +pub fn test_sync( + files: deno::deno_config::glob::FilePatterns, + config_file: PathBuf, + permissions: deno::args::PermissionFlags, + coverage_dir: Option, + filter: Option, + custom_extensions: Arc, + argv: Vec, +) { + new_thread_builder() + .spawn(|| { + create_and_run_current_thread_with_maybe_metrics(async move { + spawn_subcommand(async move { + test( + files, + config_file, + permissions, + coverage_dir, + filter, + custom_extensions, + argv, + ) + .await + .unwrap() + }) + .await + .unwrap() + }) + }) + .unwrap() + .join() + .unwrap(); +} + +pub async fn test( + files: deno::deno_config::glob::FilePatterns, + config_file: PathBuf, + permissions: deno::args::PermissionFlags, + coverage_dir: Option, + filter: Option, + custom_extensions: Arc, + argv: Vec, +) -> anyhow::Result<()> { + use deno::tools::test::*; + + deno_permissions::set_prompt_callbacks( + Box::new(deno::util::draw_thread::DrawThread::hide), + Box::new(deno::util::draw_thread::DrawThread::show), + ); + let pattern_to_str = |pattern| match pattern { + deno::deno_config::glob::PathOrPattern::Path(path) => path.to_string_lossy().to_string(), + deno::deno_config::glob::PathOrPattern::Pattern(pattern) => pattern.as_str().to_string(), + deno::deno_config::glob::PathOrPattern::RemoteUrl(url) => url.as_str().to_owned(), + deno::deno_config::glob::PathOrPattern::NegatedPath(path) => { + path.to_string_lossy().to_string() + } + }; + + let test_flags = deno::args::TestFlags { + files: deno::args::FileFlags { + include: files + .include + .clone() + .map(|set| set.into_path_or_patterns().into_iter()) + .unwrap_or_default() + .map(pattern_to_str) + .collect(), + ignore: files + .exclude + .clone() + .into_path_or_patterns() + .into_iter() + .map(pattern_to_str) + .collect(), + }, + doc: true, + trace_leaks: true, + coverage_dir, + filter, + concurrent_jobs: std::thread::available_parallelism().ok(), + ..Default::default() + }; + let flags = deno::args::Flags { + permissions, + unstable_config: deno::args::UnstableConfig { + features: DEFAULT_UNSTABLE_FLAGS + .iter() + .copied() + .map(String::from) + .collect(), + ..Default::default() + }, + type_check_mode: deno::args::TypeCheckMode::Local, + config_flag: deno::args::ConfigFlag::Path(config_file.to_string_lossy().into()), + argv, + subcommand: deno::args::DenoSubcommand::Test(test_flags.clone()), + ..Default::default() + }; + + let flags = Arc::new(flags); + + let cli_factory = + deno::factory::CliFactory::from_flags(flags).with_custom_ext_cb(custom_extensions); + + let options = cli_factory.cli_options()?.clone(); + + let test_options = deno::args::WorkspaceTestOptions { + // files, + ..options.resolve_workspace_test_options(&test_flags) + }; + let members_with_test_opts = options.resolve_test_options_for_members(&test_flags)?; + let file_fetcher = cli_factory.file_fetcher()?; + + let specifiers_with_mode = fetch_specifiers_with_test_mode( + options.as_ref(), + file_fetcher, + members_with_test_opts + .into_iter() + .map(|(_, opts)| opts.files), + &test_options.doc, + ) + .await?; + + if !test_options.permit_no_files && specifiers_with_mode.is_empty() { + return Err(deno_core::error::generic_error("No test modules found")); + } + let doc_tests = get_doc_tests(&specifiers_with_mode, file_fetcher).await?; + let specifiers_for_typecheck_and_test = get_target_specifiers(specifiers_with_mode, &doc_tests); + for doc_test in doc_tests { + file_fetcher.insert_memory_files(doc_test); + } + + let main_graph_container = cli_factory.main_module_graph_container().await?; + + // type check + main_graph_container + .check_specifiers( + &specifiers_for_typecheck_and_test, + options.ext_flag().as_ref(), + ) + .await?; + + if test_options.no_run { + return Ok(()); + } + + let worker_factory = cli_factory.create_cli_main_worker_factory().await?; + let worker_factory = Arc::new(worker_factory); + + // Various test files should not share the same permissions in terms of + // `PermissionsContainer` - otherwise granting/revoking permissions in one + // file would have impact on other files, which is undesirable. + let desc_parser = &cli_factory.permission_desc_parser()?; + let permissions = deno_permissions::Permissions::from_options( + desc_parser.as_ref(), + &options.permissions_options(), + )?; + + // run tests + test_specifiers( + worker_factory, + &permissions, + desc_parser, + specifiers_for_typecheck_and_test, + TestSpecifiersOptions { + cwd: deno_core::url::Url::from_directory_path(options.initial_cwd()).map_err(|_| { + anyhow::anyhow!( + "Unable to construct URL from the path of cwd: {}", + options.initial_cwd().to_string_lossy(), + ) + })?, + concurrent_jobs: test_options.concurrent_jobs, + fail_fast: test_options.fail_fast, + log_level: options.log_level(), + filter: test_options.filter.is_some(), + reporter: test_options.reporter, + junit_path: test_options.junit_path, + specifier: TestSpecifierOptions { + filter: TestFilter::from_flag(&test_options.filter), + shuffle: test_options.shuffle, + trace_leaks: test_options.trace_leaks, + }, + hide_stacktraces: true, + }, + ) + .await?; + + Ok(()) +} + +pub fn new_thread_builder() -> std::thread::Builder { + let builder = std::thread::Builder::new(); + let builder = if cfg!(debug_assertions) { + // deno & swc need 8 MiB with dev profile (release is ok) + // https://github.com/swc-project/swc/blob/main/CONTRIBUTING.md + builder.stack_size(8 * 1024 * 1024) + } else { + // leave default: https://doc.rust-lang.org/std/thread/#stack-size + builder + }; + builder +} diff --git a/src/denort/macros.rs b/src/denort/macros.rs new file mode 100644 index 00000000..a798aa4e --- /dev/null +++ b/src/denort/macros.rs @@ -0,0 +1,16 @@ +// Conversion that preserves source chain +// but not backtraces. +// This can be made a funciton but we have to +// depend on anyhow directly to be able to refer +// to it's Error type. +// https://github.com/eyre-rs/eyre/issues/31 +#[macro_export] +macro_rules! anyhow_to_eyre { + () => { + |err| { + eyre::format_err!(Box::::from( + err + )) + } + }; +} diff --git a/src/denort/promises.rs b/src/denort/promises.rs new file mode 100644 index 00000000..ade0ae45 --- /dev/null +++ b/src/denort/promises.rs @@ -0,0 +1,71 @@ +use crate::interlude::*; + +// Lifted from deno_core 0.318.0 +/* +MIT License + +Copyright 2018-2024 the Deno authors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + */ + +/// Wrap a promise with `then` handlers allowing us to watch the resolution progress from a Rust closure. +/// This has a side-effect of preventing unhandled rejection handlers from triggering. If that is +/// desired, the final handler may choose to rethrow the exception. +pub fn watch_promise<'s, F>( + scope: &mut v8::HandleScope<'s>, + promise: v8::Local<'s, v8::Promise>, + f: F, +) -> Option> +where + F: FnOnce( + &mut v8::HandleScope, + v8::ReturnValue, + Result, v8::Local>, + ) + 'static, +{ + let external = v8::External::new(scope, Box::into_raw(Box::new(Some(f))) as _); + + fn get_handler(external: v8::Local) -> F { + unsafe { Box::>::from_raw(external.value() as _) } + .take() + .unwrap() + } + let on_fulfilled = + |scope: &mut v8::HandleScope, args: v8::FunctionCallbackArguments, rv: v8::ReturnValue| { + let data = v8::Local::::try_from(args.data()).unwrap(); + let f = get_handler::(data); + f(scope, rv, Ok(args.get(0))); + }; + let on_fulfilled = v8::Function::builder(on_fulfilled) + .data(external.into()) + .build(scope); + + let on_rejected = + |scope: &mut v8::HandleScope, args: v8::FunctionCallbackArguments, rv: v8::ReturnValue| { + let data = v8::Local::::try_from(args.data()).unwrap(); + let f = get_handler::(data); + f(scope, rv, Err(args.get(0))); + }; + let on_rejected = v8::Function::builder(on_rejected) + .data(external.into()) + .build(scope); + // function builders will return None if the runtime is shutting down + let (Some(on_fulfilled), Some(on_rejected)) = (on_fulfilled, on_rejected) else { + _ = get_handler::(external); + return None; + }; + + // then2 will return None if the runtime is shutting down + let Some(promise) = promise.then2(scope, on_fulfilled, on_rejected) else { + _ = get_handler::(external); + return None; + }; + + Some(promise) +} diff --git a/src/denort/unsync.rs b/src/denort/unsync.rs new file mode 100644 index 00000000..0a3acacf --- /dev/null +++ b/src/denort/unsync.rs @@ -0,0 +1,280 @@ +// Modified from https://github.com/denoland/deno_unsync/blob/503a3fcb82235a591a98b497c8d26be5772c6dc9/src/tokio/task.rs +// Copyright 2018-2024 the Deno authors. MIT license. + +use core::pin::Pin; +use core::task::Context; +use core::task::Poll; +use std::future::Future; +use std::marker::PhantomData; +use tokio::runtime::Handle; +use tokio::runtime::RuntimeFlavor; + +/// Equivalent to [`tokio::task::JoinHandle`]. +#[repr(transparent)] +pub struct JoinHandle { + handle: tokio::task::JoinHandle>, + _r: PhantomData, +} + +impl JoinHandle { + /// Equivalent to [`tokio::task::JoinHandle::abort`]. + pub fn abort(&self) { + self.handle.abort() + } + + pub fn abort_handle(&self) -> tokio::task::AbortHandle { + self.handle.abort_handle() + } +} + +impl Future for JoinHandle { + type Output = Result; + + fn poll( + self: Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> std::task::Poll { + // SAFETY: We are sure that handle is valid here + unsafe { + let me: &mut Self = Pin::into_inner_unchecked(self); + let handle = Pin::new_unchecked(&mut me.handle); + match handle.poll(cx) { + Poll::Pending => Poll::Pending, + Poll::Ready(Ok(r)) => Poll::Ready(Ok(r.into_inner())), + Poll::Ready(Err(e)) => Poll::Ready(Err(e)), + } + } + } +} + +/// Equivalent to [`tokio::task::spawn`], but does not require the future to be [`Send`]. Must only be +/// used on a [`RuntimeFlavor::CurrentThread`] executor, though this is only checked when running with +/// debug assertions. +#[inline(always)] +pub fn spawn + 'static, R: 'static>(name: &str, f: F) -> JoinHandle { + debug_assert!(Handle::current().runtime_flavor() == RuntimeFlavor::CurrentThread); + // SAFETY: we know this is a current-thread executor + let future = unsafe { MaskFutureAsSend::new(f) }; + JoinHandle { + handle: tokio::task::Builder::new() + .name(name) + .spawn(future) + .expect("tokio error"), + _r: Default::default(), + } +} + +/// Equivalent to [`tokio::task::spawn_blocking`]. Currently a thin wrapper around the tokio API, but this +/// may change in the future. +#[inline(always)] +pub fn spawn_blocking R) + Send + 'static, R: Send + 'static>( + name: &str, + f: F, +) -> JoinHandle { + let handle = tokio::task::Builder::new() + .name(name) + .spawn_blocking(|| MaskResultAsSend { result: f() }) + .expect("tokio error"); + JoinHandle { + handle, + _r: Default::default(), + } +} + +#[repr(transparent)] +#[doc(hidden)] +pub struct MaskResultAsSend { + result: R, +} + +/// SAFETY: We ensure that Send bounds are only faked when tokio is running on a current-thread executor +unsafe impl Send for MaskResultAsSend {} + +impl MaskResultAsSend { + #[inline(always)] + pub fn into_inner(self) -> R { + self.result + } +} + +#[repr(transparent)] +pub struct MaskFutureAsSend { + future: F, +} + +impl MaskFutureAsSend { + /// Mark a non-`Send` future as `Send`. This is a trick to be able to use + /// `tokio::spawn()` (which requires `Send` futures) in a current thread + /// runtime. + /// + /// # Safety + /// + /// You must ensure that the future is actually used on the same + /// thread, ie. always use current thread runtime flavor from Tokio. + #[inline(always)] + pub unsafe fn new(future: F) -> Self { + Self { future } + } +} + +// SAFETY: we are cheating here - this struct is NOT really Send, +// but we need to mark it Send so that we can use `spawn()` in Tokio. +unsafe impl Send for MaskFutureAsSend {} + +impl Future for MaskFutureAsSend { + type Output = MaskResultAsSend; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + // SAFETY: We are sure that future is valid here + unsafe { + let me: &mut MaskFutureAsSend = Pin::into_inner_unchecked(self); + let future = Pin::new_unchecked(&mut me.future); + match future.poll(cx) { + Poll::Pending => Poll::Pending, + Poll::Ready(result) => Poll::Ready(MaskResultAsSend { result }), + } + } + } +} + +// Copied from https://github.com/denoland/deno_unsync/blob/503a3fcb82235a591a98b497c8d26be5772c6dc9/src/tokio/joinset.rs +// Copyright 2018-2024 the Deno authors. MIT license. +// Some code and comments under MIT license where adapted from Tokio code +// Copyright (c) 2023 Tokio Contributors + +use std::task::Waker; +use tokio::task::AbortHandle; +use tokio::task::JoinError; + +/// Wraps the tokio [`JoinSet`] to make it !Send-friendly and to make it easier and safer for us to +/// poll while empty. +pub struct JoinSet { + joinset: tokio::task::JoinSet>, + /// If join_next returns Ready(None), we stash the waker + waker: Option, +} + +impl Default for JoinSet { + fn default() -> Self { + Self { + joinset: Default::default(), + waker: None, + } + } +} + +impl JoinSet { + /// Spawn the provided task on the `JoinSet`, returning an [`AbortHandle`] + /// that can be used to remotely cancel the task. + /// + /// The provided future will start running in the background immediately + /// when this method is called, even if you don't await anything on this + /// `JoinSet`. + /// + /// # Panics + /// + /// This method panics if called outside of a Tokio runtime. + /// + /// [`AbortHandle`]: tokio::task::AbortHandle + #[track_caller] + pub fn spawn(&mut self, task: F) -> AbortHandle + where + F: Future, + F: 'static, + T: 'static, + { + // SAFETY: We only use this with the single-thread executor + let handle = self.joinset.spawn(unsafe { MaskFutureAsSend::new(task) }); + + // If someone had called poll_join_next while we were empty, ask them to poll again + // so we can properly register the waker with the underlying JoinSet. + if let Some(waker) = self.waker.take() { + waker.wake(); + } + handle + } + + #[track_caller] + pub fn spawn_named(&mut self, name: &str, task: F) -> AbortHandle + where + F: Future, + F: 'static, + T: 'static, + { + // SAFETY: We only use this with the single-thread executor + let handle = self + .joinset + .build_task() + .name(name) + .spawn(unsafe { MaskFutureAsSend::new(task) }) + .expect("tokio error"); + + // If someone had called poll_join_next while we were empty, ask them to poll again + // so we can properly register the waker with the underlying JoinSet. + if let Some(waker) = self.waker.take() { + waker.wake(); + } + handle + } + + /// Returns the number of tasks currently in the `JoinSet`. + pub fn len(&self) -> usize { + self.joinset.len() + } + + /// Returns whether the `JoinSet` is empty. + pub fn is_empty(&self) -> bool { + self.joinset.is_empty() + } + + /// Waits until one of the tasks in the set completes and returns its output. + /// + /// # Cancel Safety + /// + /// This method is cancel safe. If `join_next` is used as the event in a `tokio::select!` + /// statement and some other branch completes first, it is guaranteed that no tasks were + /// removed from this `JoinSet`. + pub fn poll_join_next(&mut self, cx: &mut Context) -> Poll> { + match self.joinset.poll_join_next(cx) { + Poll::Ready(Some(res)) => Poll::Ready(res.map(|res| res.into_inner())), + Poll::Ready(None) => { + // Stash waker + self.waker = Some(cx.waker().clone()); + Poll::Pending + } + Poll::Pending => Poll::Pending, + } + } + + /// Waits until one of the tasks in the set completes and returns its output. + /// + /// Returns `None` if the set is empty. + /// + /// # Cancel Safety + /// + /// This method is cancel safe. If `join_next` is used as the event in a `tokio::select!` + /// statement and some other branch completes first, it is guaranteed that no tasks were + /// removed from this `JoinSet`. + pub async fn join_next(&mut self) -> Option> { + self.joinset + .join_next() + .await + .map(|result| result.map(|res| res.into_inner())) + } + + /// Aborts all tasks on this `JoinSet`. + /// + /// This does not remove the tasks from the `JoinSet`. To wait for the tasks to complete + /// cancellation, you should call `join_next` in a loop until the `JoinSet` is empty. + pub fn abort_all(&mut self) { + self.joinset.abort_all(); + } + + /// Removes all tasks from this `JoinSet` without aborting them. + /// + /// The tasks removed by this call will continue to run in the background even if the `JoinSet` + /// is dropped. + pub fn detach_all(&mut self) { + self.joinset.detach_all(); + } +} diff --git a/src/denort/worker.rs b/src/denort/worker.rs new file mode 100644 index 00000000..c58fa855 --- /dev/null +++ b/src/denort/worker.rs @@ -0,0 +1,566 @@ +use crate::interlude::*; +use deno::{ + deno_runtime::{ + deno_core::{futures::FutureExt, ModuleSpecifier}, + deno_permissions, + }, + *, +}; + +// thread tag used for basic sanity checks +pub const WORKER_THREAD_NAME: &str = "denort-worker-thread"; + +/// This starts a new task to run all the work +/// that'll need to touch deno internals. +/// Deno is single threaded and this expects to run on single threaded runtimes. +/// +/// The returned handle will use channels internally to communicate to this worker. +pub async fn worker( + flags: deno::args::Flags, + custom_extensions_cb: Option>, +) -> Res { + let cx = WorkerContext::from_config(flags, custom_extensions_cb).await?; + + let (msg_tx, mut msg_rx) = tokio::sync::mpsc::channel::(32); + + let (term_signal_tx, term_signal_rx) = tokio::sync::watch::channel(false); + + let mut term_signal_rx2 = term_signal_rx.clone(); + let join_handle = crate::unsync::spawn( + "deno-worker", + async move { + let mut task_set = crate::unsync::JoinSet::default(); + trace!("starting deno worker"); + loop { + let msg = tokio::select! { + Some(msg) = msg_rx.recv() => { + msg + } + _ = term_signal_rx2.changed() => break, + else => break + }; + trace!(?msg, "deno worker msg"); + match msg { + DenoWorkerMsg::PrepareModule { + response_channel, + inner, + } => { + response_channel + .send( + module_worker(&cx, term_signal_rx2.clone(), inner, &mut task_set) + .await, + ) + .expect_or_log("channel error"); + } + } + } + // std::mem::forget(cx); + trace!("deno worker done"); + } + .instrument(tracing::trace_span!("deno-worker")), + ); + // let term_signal_tx = Arc::new(term_signal_tx); + let join_handle = Arc::new(std::sync::Mutex::new(Some(join_handle))); + Ok(DenoWorkerHandle { + sender: msg_tx, + term_signal_tx, + term_signal_rx, + join_handle, + }) +} + +type TermSignal = tokio::sync::watch::Receiver; + +async fn module_worker( + cx: &WorkerContext, + global_term_signal: TermSignal, + msg: PrepareModuleMsg, + task_set: &mut crate::unsync::JoinSet<()>, +) -> Res { + let mut module_cx = cx + .prepare_module( + msg.main_module.clone(), + &msg.permissions, + msg.mode, + msg.stdio, + msg.custom_extensions_cb, + ) + .await?; + + let (module_tx, mut module_rx) = tokio::sync::mpsc::channel::(1); + task_set.spawn_named( + &format!("deno-module-worker-{}", msg.main_module), + async move { + trace!("starting module worker"); + while let Some(msg) = module_rx.recv().await { + trace!(?msg, "module worker msg"); + match msg { + ModuleWorkerReq::Run { response_channel } => response_channel + .send(module_cx.run(global_term_signal.clone()).await) + .expect_or_log("channel error"), + ModuleWorkerReq::DriveTillExit { + term_signal, + response_channel, + } => response_channel + .send( + module_cx + .drive_till_exit(global_term_signal.clone(), term_signal) + .await + .map_err(crate::anyhow_to_eyre!()), + ) + .expect_or_log("channel error"), + ModuleWorkerReq::Execute { response_channel } => response_channel + .send( + module_cx + .execute_main_module() + .await + .map_err(crate::anyhow_to_eyre!()), + ) + .expect_or_log("channel error"), + ModuleWorkerReq::GetLoadedModules { response_channel } => response_channel + .send(module_cx.get_loaded_modules()) + .expect_or_log("channel error"), + } + } + // std::mem::forget(module_cx); + trace!("module worker done"); + } + .instrument(tracing::trace_span!( + "deno-module-worker", + main_module = %msg.main_module + )), + ); + Ok(ModuleWorkerHandle { sender: module_tx }) +} + +#[derive(educe::Educe)] +#[educe(Debug)] +struct WorkerContext { + #[educe(Debug(ignore))] + cli_factory: deno::factory::CliFactory, + #[educe(Debug(ignore))] + worker_factory: deno::worker::CliMainWorkerFactory, + #[educe(Debug(ignore))] + graph: Arc, +} + +impl WorkerContext { + async fn from_config( + flags: deno::args::Flags, + root_custom_extensions_cb: Option>, + ) -> Res { + deno_permissions::set_prompt_callbacks( + Box::new(util::draw_thread::DrawThread::hide), + Box::new(util::draw_thread::DrawThread::show), + ); + + let flags = args::Flags { ..flags }; + let flags = Arc::new(flags); + let cli_factory = factory::CliFactory::from_flags(flags); + let cli_factory = if let Some(custom_extensions_cb) = &root_custom_extensions_cb { + cli_factory.with_custom_ext_cb(custom_extensions_cb.clone()) + } else { + cli_factory + }; + let worker_factory = cli_factory + .create_cli_main_worker_factory() + .await + .map_err(|err| ferr!(Box::new(err)))?; + + let graph = cli_factory + .main_module_graph_container() + .await + .map_err(crate::anyhow_to_eyre!())? + .clone(); + Ok(Self { + cli_factory, + worker_factory, + graph, + }) + } + + async fn prepare_module( + &self, + main_module: ModuleSpecifier, + permissions: &deno_permissions::PermissionsOptions, + mode: deno_runtime::WorkerExecutionMode, + stdio: deno_runtime::deno_io::Stdio, + custom_extensions_cb: Option>, + ) -> Res { + let desc_parser = self + .cli_factory + .permission_desc_parser() + .map_err(crate::anyhow_to_eyre!())? + .clone(); + let permissions = + deno_permissions::Permissions::from_options(desc_parser.as_ref(), permissions)?; + let permissions = deno_permissions::PermissionsContainer::new(desc_parser, permissions); + let mut worker = self + .worker_factory + .create_custom_worker( + mode, + main_module.clone(), + permissions, + custom_extensions_cb, + stdio, + ) + .await + .map_err(crate::anyhow_to_eyre!())?; + let maybe_coverage_collector = worker + .maybe_setup_coverage_collector() + .await + .map_err(crate::anyhow_to_eyre!())?; + + // TODO: hot module support, expose shared worker contet from deno/cli/worker + // let maybe_hmr_runner = worker + // .maybe_setup_hmr_runner() + // .await + // .map_err(|err| ferr!(Box::new(err)))?; + + let worker = worker.into_main_worker(); + + Ok(ModuleWorkerContext { + main_module, + worker, + graph: self.graph.clone(), + maybe_coverage_collector, + // maybe_hmr_runner, + }) + } +} + +#[derive(educe::Educe)] +#[educe(Debug)] +struct PrepareModuleMsg { + main_module: ModuleSpecifier, + permissions: deno_permissions::PermissionsOptions, + #[educe(Debug(ignore))] + mode: deno_runtime::WorkerExecutionMode, + #[educe(Debug(ignore))] + stdio: deno_runtime::deno_io::Stdio, + #[educe(Debug(ignore))] + custom_extensions_cb: Option>, +} + +#[derive(educe::Educe)] +#[educe(Debug)] +enum DenoWorkerMsg { + PrepareModule { + #[educe(Debug(ignore))] + response_channel: tokio::sync::oneshot::Sender>, + inner: PrepareModuleMsg, + }, +} + +#[derive(Clone, educe::Educe)] +#[educe(Debug)] +pub struct DenoWorkerHandle { + sender: tokio::sync::mpsc::Sender, + term_signal_tx: tokio::sync::watch::Sender, + #[educe(Debug(ignore))] + join_handle: Arc>>>, + term_signal_rx: tokio::sync::watch::Receiver, +} + +impl DenoWorkerHandle { + pub fn term_signal_watcher(&self) -> tokio::sync::watch::Receiver { + self.term_signal_rx.clone() + } + + pub async fn terminate(self) -> Res<()> { + let join_handle = { + let mut opt = self.join_handle.lock().expect_or_log("mutex error"); + opt.take() + }; + let Some(join_handle) = join_handle else { + return Ok(()); + }; + self.term_signal_tx.send(true)?; + let abort_handle = join_handle.abort_handle(); + match tokio::time::timeout(std::time::Duration::from_millis(100), join_handle).await { + Ok(val) => val.wrap_err("tokio error"), + Err(_) => { + trace!("timeout waiting for deno worker termination, aborting"); + abort_handle.abort(); + Ok(()) + } + } + //join_handle.await.wrap_err("tokio error") + } +} + +impl DenoWorkerHandle { + pub async fn prepare_module( + &self, + main_module: ModuleSpecifier, + permissions: deno_permissions::PermissionsOptions, + mode: deno_runtime::WorkerExecutionMode, + stdio: deno_runtime::deno_io::Stdio, + custom_extensions_cb: Option>, + ) -> Res { + let (tx, rx) = tokio::sync::oneshot::channel(); + self.sender + .send(DenoWorkerMsg::PrepareModule { + response_channel: tx, + inner: PrepareModuleMsg { + main_module, + permissions, + mode, + stdio, + custom_extensions_cb, + }, + }) + .await + .expect_or_log("channel error"); + rx.await.expect_or_log("channel error") + } +} + +#[derive(educe::Educe)] +#[educe(Debug)] +struct ModuleWorkerContext { + main_module: deno_core::ModuleSpecifier, + #[educe(Debug(ignore))] + worker: deno_runtime::worker::MainWorker, + #[educe(Debug(ignore))] + graph: Arc, + #[educe(Debug(ignore))] + maybe_coverage_collector: Option>, + // maybe_hmr_runner: Option>, +} + +impl ModuleWorkerContext { + fn get_loaded_modules(&self) -> Vec { + use deno::graph_container::*; + self.graph + .graph() + .modules() + .map(|module| match module { + deno_graph::Module::Js(js_module) => js_module.specifier.clone(), + deno_graph::Module::Json(json_module) => json_module.specifier.clone(), + deno_graph::Module::Wasm(wasm_module) => wasm_module.specifier.clone(), + deno_graph::Module::Npm(npm_module) => npm_module.specifier.clone(), + deno_graph::Module::Node(built_in_node_module) => { + built_in_node_module.specifier.clone() + } + deno_graph::Module::External(external_module) => external_module.specifier.clone(), + }) + .collect() + } + + async fn run(&mut self, global_term_signal: TermSignal) -> Res { + debug!("main_module {}", self.main_module); + self.execute_main_module() + .await + .map_err(crate::anyhow_to_eyre!())?; + + let (_term_signal_tx, term_signal_rx) = tokio::sync::watch::channel(false); + let exit_code = self + .drive_till_exit(global_term_signal, term_signal_rx) + .await + .map_err(crate::anyhow_to_eyre!())?; + + Ok(exit_code) + } + + async fn drive_till_exit( + &mut self, + mut global_term_signal: TermSignal, + mut term_signal: TermSignal, + ) -> anyhow::Result { + self.worker.dispatch_load_event()?; + loop { + /* if let Some(hmr_runner) = self.maybe_hmr_runner.as_mut() { + let watcher_communicator = + self.shared.maybe_file_watcher_communicator.clone().unwrap(); + + let hmr_future = hmr_runner.run().boxed_local(); + let event_loop_future = self.worker.run_event_loop(false).boxed_local(); + + let result; + tokio::select! { + hmr_result = hmr_future => { + result = hmr_result; + }, + event_loop_result = event_loop_future => { + result = event_loop_result; + } + } + if let Err(e) = result { + watcher_communicator.change_restart_mode(WatcherRestartMode::Automatic); + return Err(e); + } + } else { + self.worker + .run_event_loop(self.maybe_coverage_collector.is_none()) + .await?; + } */ + + let event_loop_future = self + .worker + .run_event_loop(self.maybe_coverage_collector.is_none()) + .boxed_local(); + + trace!("running event loop"); + tokio::select! { + _ = global_term_signal.wait_for(|sig| *sig) => { + trace!("global term signal lit, shutting down event loop"); + break + }, + _ = term_signal.wait_for(|sig| *sig) => { + trace!("worker term signal lit, shutting down event loop"); + break + }, + event_loop_result = event_loop_future => { + anyhow::Context::context(event_loop_result, "event loop error")?; + } + } + + let web_continue = self.worker.dispatch_beforeunload_event()?; + if !web_continue { + let node_continue = self.worker.dispatch_process_beforeexit_event()?; + if !node_continue { + trace!("beforeunload and beforeexit success, shutting down loop"); + break; + } + } + } + self.worker.dispatch_unload_event()?; + self.worker.dispatch_process_exit_event()?; + if let Some(coverage_collector) = self.maybe_coverage_collector.as_mut() { + self.worker + .js_runtime + .with_event_loop_future( + coverage_collector.stop_collecting().boxed_local(), + deno_core::PollEventLoopOptions::default(), + ) + .await?; + } + /* if let Some(hmr_runner) = self.maybe_hmr_runner.as_mut() { + self.worker + .js_runtime + .with_event_loop_future( + hmr_runner.stop().boxed_local(), + deno_core::PollEventLoopOptions::default(), + ) + .await?; + } */ + Ok(self.worker.exit_code()) + } + + async fn execute_main_module(&mut self) -> anyhow::Result<()> { + let id = self.worker.preload_main_module(&self.main_module).await?; + self.worker.evaluate_module(id).await + } +} + +#[derive(educe::Educe)] +#[educe(Debug)] +enum ModuleWorkerReq { + Run { + #[educe(Debug(ignore))] + response_channel: tokio::sync::oneshot::Sender>, + }, + DriveTillExit { + term_signal: TermSignal, + #[educe(Debug(ignore))] + response_channel: tokio::sync::oneshot::Sender>, + }, + Execute { + #[educe(Debug(ignore))] + response_channel: tokio::sync::oneshot::Sender>, + }, + GetLoadedModules { + #[educe(Debug(ignore))] + response_channel: tokio::sync::oneshot::Sender>, + }, +} + +#[derive(Clone, Debug)] +pub struct ModuleWorkerHandle { + sender: tokio::sync::mpsc::Sender, +} + +#[derive(Clone, Debug)] +pub struct FinishedWorkerHandle { + sender: tokio::sync::mpsc::Sender, +} + +#[derive(Debug)] +pub struct ActiveWorkerHandle { + pub exit_code_rx: tokio::sync::oneshot::Receiver>, + pub term_signal_tx: tokio::sync::watch::Sender, + pub finished: FinishedWorkerHandle, +} + +impl ModuleWorkerHandle { + /// Load and execute the main module + /// and drive the main loop until the program + /// exits. + pub async fn run(self) -> Res<(i32, FinishedWorkerHandle)> { + let (result_tx, result_rx) = tokio::sync::oneshot::channel(); + self.sender + .send(ModuleWorkerReq::Run { + response_channel: result_tx, + }) + .await + .expect_or_log("channel error"); + Ok(( + result_rx.await.expect_or_log("channel error")?, + FinishedWorkerHandle { + sender: self.sender, + }, + )) + } + + /// Load and execute the main module + /// but doesn't progress the main event + /// loop. + pub async fn execute(&mut self) -> Res<()> { + let (tx, rx) = tokio::sync::oneshot::channel(); + self.sender + .send(ModuleWorkerReq::Execute { + response_channel: tx, + }) + .await + .expect_or_log("channel error"); + rx.await.expect_or_log("channel error") + } + + /// Drive the event loop until exit and return + /// result in returned channel or the term signal + /// is lit. + /// Expects that [`execute`] was called first on the worker. + pub async fn drive_till_exit(self) -> Res { + let (term_signal_tx, term_signal_rx) = tokio::sync::watch::channel(false); + let (exit_code_tx, exit_code_rx) = tokio::sync::oneshot::channel(); + self.sender + .send(ModuleWorkerReq::DriveTillExit { + term_signal: term_signal_rx, + response_channel: exit_code_tx, + }) + .await + .expect_or_log("channel error"); + Ok(ActiveWorkerHandle { + exit_code_rx, + term_signal_tx, + finished: FinishedWorkerHandle { + sender: self.sender, + }, + }) + } +} + +impl FinishedWorkerHandle { + pub async fn get_loaded_modules(&mut self) -> Vec { + let (tx, rx) = tokio::sync::oneshot::channel(); + self.sender + .send(ModuleWorkerReq::GetLoadedModules { + response_channel: tx, + }) + .await + .expect_or_log("channel error"); + // FIXME: can use sync oneshot here? + rx.await.expect_or_log("channel error") + } +} diff --git a/src/ghjk/Cargo.toml b/src/ghjk/Cargo.toml new file mode 100644 index 00000000..c6b652ee --- /dev/null +++ b/src/ghjk/Cargo.toml @@ -0,0 +1,80 @@ +[package] +name = "ghjk" +description = "Program your development environments." +version.workspace = true +edition.workspace = true + +[[bin]] +name = "ghjk" +path = "main.rs" + +[dependencies] +denort.workspace = true +deno_core.workspace = true + +serde = "1" +serde_json = "1" + +ahash = { version = "0.8", features = ["serde"] } +indexmap = { version = "2.6.0", features = ["serde"] } +# serde_repr = { version = "0.1" } + +regex = "1.10" + +rand = "0.8" +time = { version = "0.3", features = ["serde"] } +nix = { version = "0.29.0", features = ["signal"] } + +once_cell = "1.19" +parking_lot = "0.12" +bitflags = "2.6" +itertools = "0.13" + +smallvec = { version = "1", features = [ + "serde", + "const_generics", + "const_new", + "union", +] } +smartstring = { version = "1", features = ["serde"] } + +educe.workspace = true + +thiserror = "1" +tracing-error = "0.2" +tracing-unwrap.workspace = true + +color-eyre.workspace = true +anyhow.workspace = true + +tracing.workspace = true +tracing-subscriber.workspace = true +tracing-appender = "0.2" +tracing-futures = "0.2" + +async-trait = "0.1.83" +futures = { version = "=0.3.30", default-features = false, features = ["std", "async-await"] } +tokio = { workspace = true, features = ["full", "parking_lot", "tracing"] } +tokio-stream = "0.1" + +dashmap = { version = "5.5", features = ["serde"]} + +clap = { workspace = true, features = ["derive", "env"] } +clap_complete = "=4.5.24" +shadow-rs.workspace = true +# TODO: support more config formats +config = { version = "0.14.1", default-features = false, features = ["async", "json5", "json"] } + +multihash = "0.19.2" +json-canon = "0.1.3" +data-encoding = "2.6.0" +sha2 = "0.10.8" + +pathdiff = "0.2.2" +directories = "5.0.1" +dialoguer = "0.11.0" +console = "0.15.8" +console-subscriber = { version = "0.4.1", optional = true } + +[build-dependencies] +shadow-rs.workspace = true diff --git a/src/ghjk/build.rs b/src/ghjk/build.rs new file mode 100644 index 00000000..4a0dfc45 --- /dev/null +++ b/src/ghjk/build.rs @@ -0,0 +1,3 @@ +fn main() -> shadow_rs::SdResult<()> { + shadow_rs::new() +} diff --git a/src/ghjk/cli.rs b/src/ghjk/cli.rs new file mode 100644 index 00000000..75692e17 --- /dev/null +++ b/src/ghjk/cli.rs @@ -0,0 +1,442 @@ +use std::process::ExitCode; + +use clap::builder::styling::AnsiColor; + +use crate::config::Config; +use crate::interlude::*; + +use crate::systems::{CliCommandAction, SystemCliCommand}; +use crate::{host, systems}; + +const DENO_UNSTABLE_FLAGS: &[&str] = &["worker-options", "kv"]; + +pub async fn cli() -> Res { + /* tokio::spawn({ + async { + loop { + println!("{:?}: thread is not blocked", std::thread::current().id()); + tokio::time::sleep(std::time::Duration::from_secs(2)).await; + } + } + }); */ + + let cwd = std::env::current_dir()?; + + let config = Config::source().await?; + + debug!("config sourced: {config:?}"); + + let Some(quick_err) = try_quick_cli(&config).await? else { + return Ok(ExitCode::SUCCESS); + }; + + let Some(ghjkdir_path) = config.ghjkdir.clone() else { + quick_err.exit(); + }; + + let deno_cx = { + // TODO: DENO_FLAGS param simlar to V8_FLAGS + let flags = denort::deno::args::Flags { + unstable_config: denort::deno::args::UnstableConfig { + features: DENO_UNSTABLE_FLAGS + .iter() + .copied() + .map(String::from) + .collect(), + ..default() + }, + no_lock: config.deno_lockfile.is_none(), + lock: config + .deno_lockfile + .as_ref() + .map(|path| path.to_string_lossy().into()), + internal: deno::args::InternalFlags { + cache_path: Some(config.deno_dir.clone()), + ..default() + }, + ..default() + }; + denort::worker::worker(flags, Some(Arc::new(Vec::new))).await? + }; + + let gcx = GhjkCtx { + config, + deno: deno_cx.clone(), + }; + let gcx = Arc::new(gcx); + + let (systems_deno, deno_sys_cx) = systems::deno::systems_from_deno( + &gcx, + &gcx.config + .repo_root + .join("src/deno_systems/mod.ts") + .wrap_err("repo url error")?, + &ghjkdir_path, + ) + .await?; + + let hcx = host::HostCtx::new( + gcx.clone(), + host::Config { + env_vars: std::env::vars().collect(), + cwd, + // TODO: env vars, flags and tests for the following + re_resolve: false, + locked: false, + re_serialize: false, + }, + systems_deno, + ); + + let hcx = Arc::new(hcx); + + let Some(mut systems) = host::systems_from_ghjkfile(hcx, &ghjkdir_path).await? else { + warn!("no ghjkfile found"); + quick_err.exit() + }; + + // let conf_json = serde_json::to_string_pretty(&systems.config)?; + // info!(%conf_json); + + use clap::*; + + let mut root_cmd = Cli::command(); + + debug!("collecting system commands"); + + let (sys_cmds, sys_actions) = match commands_from_systems(&systems).await { + Ok(val) => val, + Err(err) => { + systems.write_lockfile_or_log().await; + return Err(err); + } + }; + + for cmd in sys_cmds { + root_cmd = root_cmd.subcommand(cmd); + } + + debug!("checking argv matches"); + + let matches = match root_cmd.try_get_matches() { + Ok(val) => val, + Err(err) => { + systems.write_lockfile_or_log().await; + err.exit(); + } + }; + + match QuickComands::from_arg_matches(&matches) { + Ok(QuickComands::Print { commands }) => { + _ = commands.action(&gcx.config, Some(&systems.config))?; + return Ok(ExitCode::SUCCESS); + } + Ok(QuickComands::Deno { .. }) => { + unreachable!("deno quick cli will prevent this") + } + Err(err) => { + let kind = err.kind(); + use clap::error::ErrorKind; + if !(kind == ErrorKind::InvalidSubcommand + || kind == ErrorKind::InvalidValue + || kind == ErrorKind::DisplayHelp + || kind == ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand) + { + systems.write_lockfile_or_log().await; + err.exit(); + } + } + } + + let (cmd_path, mut action, action_matches) = match action_for_match(sys_actions, &matches).await + { + Ok(val) => val, + Err(err) => { + systems.write_lockfile_or_log().await; + return Err(err); + } + }; + + debug!(?cmd_path, "system command found"); + let Some(action) = action.action else { + systems.write_lockfile_or_log().await; + action.clap.print_long_help()?; + return Ok(std::process::ExitCode::FAILURE); + }; + + let res = action(action_matches.clone()) + .await + .wrap_err_with(|| format!("error on system command at path {cmd_path:?}")); + + systems.write_lockfile_or_log().await; + + deno_sys_cx.terminate().await?; + deno_cx.terminate().await?; + + res.map(|()| ExitCode::SUCCESS) +} + +/// Sections of the CLI do not require loading a ghjkfile. +pub async fn try_quick_cli(config: &Config) -> Res> { + use clap::*; + + let cli = match Cli::try_parse() { + Ok(val) => val, + Err(err) => { + let kind = err.kind(); + use clap::error::ErrorKind; + if kind == ErrorKind::InvalidSubcommand + || kind == ErrorKind::InvalidValue + || kind == ErrorKind::DisplayHelp + || kind == ErrorKind::DisplayHelpOnMissingArgumentOrSubcommand + { + return Ok(Some(err)); + } + err.exit(); + } + }; + + match cli.quick_commands { + QuickComands::Print { commands } => { + if !commands.action(config, None)? { + return Ok(Some(clap::error::Error::new( + clap::error::ErrorKind::DisplayHelp, + ))); + } + } + QuickComands::Deno { .. } => unreachable!("deno quick cli will have prevented this"), + } + + Ok(None) +} + +const CLAP_STYLE: clap::builder::Styles = clap::builder::Styles::styled() + .header(AnsiColor::Yellow.on_default()) + .usage(AnsiColor::BrightBlue.on_default()) + .literal(AnsiColor::BrightBlue.on_default()) + .placeholder(AnsiColor::BrightBlue.on_default()); + +#[derive(Debug, clap::Parser)] +#[clap( + version, + about, + styles = CLAP_STYLE +)] +struct Cli { + #[command(subcommand)] + quick_commands: QuickComands, +} + +#[derive(clap::Subcommand, Debug)] +enum QuickComands { + /// Print different discovored or built values to stdout. + Print { + #[command(subcommand)] + commands: PrintCommands, + }, + /// Access the deno cli + Deno { + #[arg(raw(true))] + args: String, + }, +} + +#[derive(clap::Subcommand, Debug)] +enum PrintCommands { + /// Print the path to the data dir used by ghjk. + DataDirPath, + /// Print the path to the dir of the currently active ghjk context. + GhjkdirPath, + /// Print the path of the ghjkfile used. + GhjkfilePath, + /// Print the extracted and serialized config from the ghjkfile. + Config { + /// Use json format when printing config. + #[arg(long)] + json: bool, + }, +} + +impl PrintCommands { + /// The return value specifies weather or not the CLI is done or + /// weather it should continue on with serialization if this + /// action was invoked as part of the quick cli + fn action( + self, + cli_config: &Config, + serialized_config: Option<&host::SerializedConfig>, + ) -> Res { + Ok(match self { + PrintCommands::DataDirPath => { + println!("{}", cli_config.data_dir.display()); + true + } + // TODO: rename GHJK_DIR to GHJKDIR + PrintCommands::GhjkdirPath => { + if let Some(path) = &cli_config.ghjkdir { + // TODO: graceful termination on SIGPIPE + println!("{}", path.display()); + true + } else { + eyre::bail!("no ghjkdir found."); + } + } + PrintCommands::GhjkfilePath => { + if let Some(path) = &cli_config.ghjkdir { + println!("{}", path.display()); + true + } else { + eyre::bail!("no ghjkfile found."); + } + } + PrintCommands::Config { .. } => match serialized_config { + Some(config) => { + let conf_json = serde_json::to_string_pretty(&config)?; + println!("{conf_json}"); + true + } + None => false, + }, + }) + } +} + +type SysCmdActions = IndexMap; +struct SysCmdAction { + name: CHeapStr, + clap: clap::Command, + action: Option, + sub_commands: SysCmdActions, +} + +async fn commands_from_systems( + systems: &host::GhjkfileSystems, +) -> Res<(Vec, SysCmdActions)> { + fn inner(cmd: SystemCliCommand) -> (SysCmdAction, clap::Command) { + // apply styles here due to propagation + // breaking for these dynamic subcommands for some reason + let mut clap_cmd = cmd.clap.styles(CLAP_STYLE); + let mut sub_commands = IndexMap::new(); + for (id, cmd) in cmd.sub_commands { + let (sub_sys_cmd, sub_cmd) = inner(cmd); + clap_cmd = clap_cmd.subcommand(sub_cmd); + sub_commands.insert(id, sub_sys_cmd); + } + ( + SysCmdAction { + clap: clap_cmd.clone(), + name: cmd.name, + action: cmd.action, + sub_commands, + }, + clap_cmd, + ) + } + let mut commands = vec![]; + let mut conflict_tracker = HashMap::new(); + let mut actions = SysCmdActions::new(); + for (id, sys_inst) in &systems.sys_instances { + let cmds = sys_inst + .commands() + .await + .wrap_err_with(|| format!("error getting commands for system: {id}"))?; + for cmd in cmds { + let (sys_cmd, clap_cmd) = inner(cmd); + + if let Some(conflict) = conflict_tracker.insert(sys_cmd.name.clone(), id) { + eyre::bail!( + "system commannd conflict under name {:?} for modules {conflict:?} and {id:?}", + sys_cmd.name.clone(), + ); + } + actions.insert(sys_cmd.name.clone(), sys_cmd); + commands.push(clap_cmd); + } + } + Ok((commands, actions)) +} + +async fn action_for_match( + mut actions: SysCmdActions, + matches: &clap::ArgMatches, +) -> Res<(Vec, SysCmdAction, &clap::ArgMatches)> { + fn inner<'a>( + mut current: SysCmdAction, + matches: &'a clap::ArgMatches, + cmd_path: &mut Vec, + ) -> Res<(SysCmdAction, &'a clap::ArgMatches)> { + match matches.subcommand() { + Some((cmd_name, matches)) => { + cmd_path.push(cmd_name.into()); + match current.sub_commands.swap_remove(cmd_name) { + Some(action) => inner(action, matches, cmd_path), + None => { + eyre::bail!("no match found for cmd {cmd_path:?}") + } + } + } + None => Ok((current, matches)), + } + } + let mut cmd_path = vec![]; + let Some((cmd_name, matches)) = matches.subcommand() else { + unreachable!("clap prevents this branch") + }; + cmd_path.push(cmd_name.into()); + let Some(action) = actions.swap_remove(cmd_name) else { + eyre::bail!("no match found for cmd {cmd_path:?}"); + }; + let (action, matches) = inner(action, matches, &mut cmd_path)?; + Ok((cmd_path, action, matches)) +} + +/// TODO: keep more of this in deno next time it's updated +pub fn deno_quick_cli() -> Option<()> { + let argv = std::env::args_os().skip(1).collect::>(); + let first = argv.first()?; + if first != "deno" { + return None; + } + deno::util::unix::raise_fd_limit(); + deno::util::windows::ensure_stdio_open(); + deno_runtime::deno_permissions::set_prompt_callbacks( + Box::new(deno::util::draw_thread::DrawThread::hide), + Box::new(deno::util::draw_thread::DrawThread::show), + ); + + let future = async move { + // NOTE(lucacasonato): due to new PKU feature introduced in V8 11.6 we need to + // initialize the V8 platform on a parent thread of all threads that will spawn + // V8 isolates. + let flags = deno::resolve_flags_and_init(argv)?; + deno::run_subcommand(Arc::new(flags)).await + }; + + let result = deno_runtime::tokio_util::create_and_run_current_thread_with_maybe_metrics(future); + + match result { + Ok(exit_code) => deno_runtime::exit(exit_code), + Err(err) => exit_for_error(err), + } +} + +fn exit_with_message(message: &str, code: i32) -> ! { + tracing::error!("error: {}", message.trim_start_matches("error: ")); + deno_runtime::exit(code); +} + +fn exit_for_error(error: anyhow::Error) -> ! { + let mut error_string = format!("{error:?}"); + let error_code = 1; + + if let Some(e) = error.downcast_ref::() { + error_string = deno_runtime::fmt_errors::format_js_error(e); + } /* else if let Some(SnapshotFromLockfileError::IntegrityCheckFailed(e)) = + error.downcast_ref::() + { + error_string = e.to_string(); + error_code = 10; + } */ + + exit_with_message(&error_string, error_code); +} diff --git a/src/ghjk/config.rs b/src/ghjk/config.rs new file mode 100644 index 00000000..5157c901 --- /dev/null +++ b/src/ghjk/config.rs @@ -0,0 +1,286 @@ +use crate::interlude::*; + +#[derive(Debug)] +pub struct Config { + pub ghjkfile: Option, + pub ghjkdir: Option, + pub data_dir: PathBuf, + pub deno_dir: PathBuf, + pub deno_lockfile: Option, + pub repo_root: url::Url, +} + +#[derive(Deserialize)] +struct GlobalConfigFile { + data_dir: Option, + deno_dir: Option, + repo_root: Option, +} + +#[derive(Deserialize)] +struct LocalConfigFile { + #[serde(flatten)] + global: GlobalConfigFile, + deno_lockfile: Option, +} + +impl Config { + pub async fn source() -> Res { + let cwd = std::env::current_dir()?; + let xdg_dirs = directories::ProjectDirs::from("", "", "ghjk") + .expect_or_log("unable to resolve home dir"); + + let ghjkdir_path = match path_from_env(&cwd, "GHJK_DIR")? { + Some(val) => Some(val), + None => crate::utils::find_entry_recursive(&cwd, ".ghjk") + .await + .wrap_err("error trying to locate a .ghjk dir")?, + }; + + let ghjkfile_path = match path_from_env(&cwd, "GHJKFILE")? { + Some(val) => Some(val), + None => { + // NOTE: look for typescript ghjkfile + let ghjkfile_name = "ghjk.ts"; + match &ghjkdir_path { + Some(ghjkfile_path) => { + crate::utils::find_entry_recursive( + ghjkfile_path + .parent() + .expect_or_log("invalid GHJK_DIR path"), + ghjkfile_name, + ) + .await? + } + None => crate::utils::find_entry_recursive(&cwd, ghjkfile_name) + .await + .wrap_err_with(|| { + format!("error trying to locate a ghjkfile of kind \"{ghjkfile_name}\"") + })?, + } + } + }; + + // if ghjkfile var is set, set the GHJK_DIR overriding + // any set by the user + let (ghjkfile_path, ghjkdir_path) = if let Some(path) = ghjkfile_path { + let file_path = tokio::fs::canonicalize(&path) + .await + .wrap_err_with(|| format!("error canonicalizing ghjkfile path at {path:?}"))?; + let dir_path = file_path.parent().unwrap().join(".ghjk"); + (Some(file_path), Some(dir_path)) + } else { + (None, ghjkdir_path) + }; + + if ghjkdir_path.is_none() && ghjkfile_path.is_none() { + warn!( + "ghjk could not find any ghjkfiles or ghjkdirs, try creating a `ghjk.ts` script.", + ); + } + + let mut config = Config { + ghjkfile: ghjkfile_path, + ghjkdir: ghjkdir_path.clone(), + data_dir: xdg_dirs.data_dir().to_owned(), + deno_dir: xdg_dirs.data_dir().join("deno"), + deno_lockfile: ghjkdir_path.as_ref().map(|path| path.join("deno.lock")), + repo_root: { + if cfg!(debug_assertions) { + url::Url::from_file_path(&cwd) + .expect_or_log("cwd error") + .join(&format!("{}/", cwd.file_name().unwrap().to_string_lossy())) + .wrap_err("repo url error")? + } else { + const BASE_URL: &str = + "https://raw.githubusercontent.com/metatypedev/metatype/"; + // repo root url must end in slash due to + // how Url::join works + let url = BASE_URL.to_owned() + crate::shadow::COMMIT_HASH + "/"; + url::Url::parse(&url).expect("repo url error") + } + }, + }; + + let global_config_path = match path_from_env(&cwd, "GHJK_CONFIG_DIR")? { + Some(val) => val, + None => xdg_dirs.config_dir().join("config"), + }; + + // we use builtin config-rs File implementation + // which relies on sync std + let config = tokio::task::spawn_blocking(move || { + { + config + .source_global_config(&global_config_path) + .wrap_err_with(|| { + format!("error sourcing global config from {global_config_path:?}") + })?; + } + + if let Some(ghjkdir_path) = &ghjkdir_path { + let file_path = ghjkdir_path.join("config"); + config + .source_local_config(&file_path) + .wrap_err_with(|| format!("error sourcing local config from {file_path:?}"))?; + }; + + config + .source_env_config(&cwd) + .wrap_err("error sourcing config from environment variables")?; + + if !config.repo_root.path().ends_with("/") { + config + .repo_root + .set_path(&format!("{}/", config.repo_root.path())); + } + + eyre::Ok(config) + }) + .await + .expect_or_log("tokio error")?; + + if let Some(path) = &config.ghjkdir { + let ignore_path = path.join(".gitignore"); + if !matches!(tokio::fs::try_exists(&ignore_path).await, Ok(true)) { + tokio::fs::create_dir_all(path) + .await + .wrap_err_with(|| format!("error creating ghjkdir at {path:?}"))?; + tokio::fs::write( + &ignore_path, + "envs +hash.json", + ) + .await + .wrap_err_with(|| format!("error writing ignore file at {ignore_path:?}"))?; + } + } + Ok(config) + } + + fn source_global_config(&mut self, file_path: &Path) -> Res<()> { + let GlobalConfigFile { + deno_dir, + data_dir, + repo_root, + } = config::Config::builder() + .add_source(config::File::with_name(&file_path.to_string_lossy()[..]).required(false)) + .build() + .wrap_err("error reading config file")? + .try_deserialize() + .wrap_err("error deserializing config file")?; + if let Some(path) = data_dir { + self.data_dir = + resolve_config_path(&path, file_path).wrap_err("error resolving data_dir")?; + } + if let Some(path) = deno_dir { + self.deno_dir = + resolve_config_path(&path, file_path).wrap_err("error resolving deno_dir")?; + } + if let Some(path) = repo_root { + self.repo_root = deno_core::resolve_url_or_path(&path, file_path) + .map_err(|err| ferr!(Box::new(err))) + .wrap_err("error resolving repo_root")?; + } + Ok(()) + } + + fn source_local_config(&mut self, file_path: &Path) -> Res<()> { + let LocalConfigFile { + global: + GlobalConfigFile { + data_dir, + deno_dir, + repo_root, + }, + deno_lockfile, + } = config::Config::builder() + .add_source(config::File::with_name(&file_path.to_string_lossy()).required(false)) + .build() + .wrap_err("error reading config file")? + .try_deserialize() + .wrap_err("error deserializing config file")?; + + if let Some(path) = data_dir { + self.data_dir = + resolve_config_path(&path, file_path).wrap_err("error resolving data_dir")?; + } + if let Some(path) = deno_dir { + self.deno_dir = + resolve_config_path(&path, file_path).wrap_err("error resolving deno_dir")?; + } + if let Some(path) = deno_lockfile { + self.deno_lockfile = Some( + resolve_config_path(&path, file_path).wrap_err("error resolving deno_lockfile")?, + ); + } + if let Some(path) = repo_root { + self.repo_root = deno_core::resolve_url_or_path(&path, file_path) + .map_err(|err| ferr!(Box::new(err))) + .wrap_err("error resolving repo_root")?; + } + Ok(()) + } + + fn source_env_config(&mut self, cwd: &Path) -> Res<()> { + let LocalConfigFile { + global: + GlobalConfigFile { + data_dir, + deno_dir, + repo_root, + }, + deno_lockfile, + } = config::Config::builder() + .add_source(config::Environment::with_prefix("GHJK")) + .build() + .wrap_err("error reading config file")? + .try_deserialize() + .wrap_err("error deserializing config file")?; + + if let Some(path) = data_dir { + self.data_dir = resolve_config_path(&path, cwd).wrap_err("error resolving data_dir")?; + } + if let Some(path) = deno_dir { + self.deno_dir = resolve_config_path(&path, cwd).wrap_err("error resolving deno_dir")?; + } + if let Some(path) = deno_lockfile { + self.deno_lockfile = if path != "off" { + Some(resolve_config_path(&path, cwd).wrap_err("error resolving deno_lockfile")?) + } else { + None + }; + } + if let Some(path) = repo_root { + self.repo_root = deno_core::resolve_url_or_path(&path, cwd) + .map_err(|err| ferr!(Box::new(err))) + .wrap_err("error resolving repo_root")?; + } + Ok(()) + } +} + +fn resolve_config_path(path: impl AsRef, config_path: &Path) -> Res { + let path = config_path.join(&path); + let path = std::path::absolute(&path) + .wrap_err_with(|| format!("error absolutizing path at {path:?}"))?; + Ok(path) +} + +fn path_from_env(cwd: &Path, env_name: &str) -> Res> { + let path = match std::env::var(env_name) { + Ok(path) => Some(PathBuf::from(path)), + Err(std::env::VarError::NotUnicode(os_str)) => Some(PathBuf::from(os_str)), + Err(std::env::VarError::NotPresent) => None, + }; + + if let Some(path) = path { + let path = cwd.join(&path); + + Ok(Some(std::path::absolute(&path).wrap_err_with(|| { + format!("error absolutizing path {path:?} from env ${env_name}") + })?)) + } else { + Ok(None) + } +} diff --git a/src/ghjk/ext.rs b/src/ghjk/ext.rs new file mode 100644 index 00000000..e46ee334 --- /dev/null +++ b/src/ghjk/ext.rs @@ -0,0 +1,226 @@ +use crate::interlude::*; + +use std::{cell::RefCell, rc::Rc}; + +use deno_core::OpState; +use tokio::sync::mpsc; +#[rustfmt::skip] +use deno_core as deno_core; // necessary for re-exported macros to work + +mod callbacks; +pub use callbacks::CallbacksHandle; + +/// This extension assumes that deno was launched on top of a tokio::LocalSet +pub fn extensions(config: ExtConfig) -> Arc { + // let atom = std::sync::atomic::AtomicBool::new(false); + Arc::new(move || { + // if atom.load(std::sync::atomic::Ordering::SeqCst) { + // return vec![]; + // } + // atom.store(true, std::sync::atomic::Ordering::SeqCst); + vec![ghjk_deno_ext::init_ops_and_esm(config.clone())] + }) +} +// This is used to populate the deno_core::OpState with dependencies +// used by the different ops +#[derive(Clone, Default)] +pub struct ExtConfig { + pub blackboard: Arc>, + callbacks_rx: Arc>, + exception_tx: Option>, + pub hostcalls: Hostcalls, +} + +impl ExtConfig { + pub fn new() -> Self { + Self::default() + } + + pub fn callbacks_handle( + &mut self, + dworker: &denort::worker::DenoWorkerHandle, + ) -> callbacks::CallbacksHandle { + let (line, handle) = callbacks::CallbackLine::new(dworker); + self.callbacks_rx = Arc::new(std::sync::Mutex::new(line)); + + handle + } + + pub fn exceptions_rx(&mut self) -> mpsc::UnboundedReceiver { + let (tx, rx) = mpsc::unbounded_channel(); + self.exception_tx = Some(tx); + rx + } + + fn inject(self, state: &mut deno_core::OpState) { + let callbacks = callbacks::worker(&self); + let ctx = ExtContext { + config: self, + callbacks, + }; + state.put(ctx); + } +} + +deno_core::extension!( + ghjk_deno_ext, + ops = [ + op_blackboard_get, + op_blackboard_set, + callbacks::op_callbacks_set, + op_hostcall, + op_dispatch_exception2 + ], + options = { config: ExtConfig }, + state = |state, opt| { + opt.config.inject(state); + }, + customizer = customizer, + docs = "Kitchen sink extension for all ghjk needs.", +); + +fn customizer(ext: &mut deno_core::Extension) { + ext.esm_files + .to_mut() + .push(deno_core::ExtensionFileSource::new( + "ext:ghjk_deno_ext/00_runtime.js", + deno_core::ascii_str_include!("js/00_runtime.js"), + )); + ext.esm_entry_point = Some("ext:ghjk_deno_ext/00_runtime.js"); +} + +#[derive(Clone)] +struct ExtContext { + callbacks: Option, + config: ExtConfig, +} + +#[deno_core::op2] +#[serde] +pub fn op_blackboard_get( + #[state] ctx: &ExtContext, + #[string] key: &str, +) -> Option { + ctx.config.blackboard.get(key).map(|val| val.clone()) +} + +#[deno_core::op2] +#[serde] +pub fn op_blackboard_set( + #[state] ctx: &ExtContext, + #[string] key: String, + #[serde] val: serde_json::Value, +) -> Option { + ctx.config.blackboard.insert(key.into(), val) +} + +#[derive(Clone, Default)] +pub struct Hostcalls { + pub funcs: Arc>, +} + +pub type HostcallFn = Box< + dyn Fn(serde_json::Value) -> BoxFuture<'static, Res> + 'static + Send + Sync, +>; + +#[deno_core::op2(async)] +#[serde] +pub async fn op_hostcall( + state: Rc>, + #[string] name: String, + #[serde] args: serde_json::Value, +) -> anyhow::Result { + let ctx = { + let state = state.borrow(); + let ctx = state.borrow::(); + ctx.clone() + }; + let Some(func) = ctx.config.hostcalls.funcs.get(&name[..]) else { + anyhow::bail!("no hostcall found under {name}"); + }; + func(args).await.map_err(|err| anyhow::anyhow!(err)) +} + +#[deno_core::op2(fast)] +pub fn op_dispatch_exception2( + scope: &mut v8::HandleScope, + #[state] ctx: &ExtContext, + exception: v8::Local, +) -> bool { + if let Some(tx) = &ctx.config.exception_tx { + tx.send(ferr!(js_error_message(scope, exception)).wrap_err("unhandledrejection")) + .expect_or_log("channel error"); + true + } else { + false + } +} + +fn js_error_message(scope: &mut v8::HandleScope, err: v8::Local) -> String { + let Some(obj) = err.to_object(scope) else { + return err.to_rust_string_lossy(scope); + }; + let evt_err_class = { + let name = v8::String::new(scope, "ErrorEvent") + .expect_or_log("v8 error") + .into(); + scope + .get_current_context() + // classes are stored on the global obj + .global(scope) + .get(scope, name) + .expect_or_log("v8 error") + .to_object(scope) + .expect_or_log("v8 error") + }; + if !obj + .instance_of(scope, evt_err_class) + .expect_or_log("v8 error") + { + for key in &["stack", "message"] { + let key = v8::String::new(scope, key).expect_or_log("v8 error"); + if let Some(inner) = obj.get(scope, key.into()) { + if inner.boolean_value(scope) { + return inner.to_rust_string_lossy(scope); + } + } + } + return err.to_rust_string_lossy(scope); + } + // ErrorEvents are recieved here for some reason + // https://developer.mozilla.org/en-US/docs/Web/API/ErrorEvent + { + // if it has an error value attached, prefer that + let key = v8::String::new(scope, "error") + .expect_or_log("v8 error") + .into(); + if let Some(inner) = obj.get(scope, key) { + // check if it's not null or undefined + if inner.boolean_value(scope) { + // stack messages are preferred if it has one + let Some(inner) = inner.to_object(scope) else { + return inner.to_rust_string_lossy(scope); + }; + let key = v8::String::new(scope, "stack").expect_or_log("v8 error"); + if let Some(stack) = inner.get(scope, key.into()) { + if stack.boolean_value(scope) { + return stack.to_rust_string_lossy(scope); + } + } + return inner.to_rust_string_lossy(scope); + } + } + } + #[derive(Deserialize)] + struct ErrorEvt { + lineno: i64, + colno: i64, + filename: String, + message: String, + } + let evt: ErrorEvt = serde_v8::from_v8(scope, err).unwrap(); + format!( + "{} ({}:{}:{})", + evt.message, evt.filename, evt.lineno, evt.colno + ) +} diff --git a/src/ghjk/ext/callbacks.rs b/src/ghjk/ext/callbacks.rs new file mode 100644 index 00000000..4a319fe6 --- /dev/null +++ b/src/ghjk/ext/callbacks.rs @@ -0,0 +1,317 @@ +use std::{cell::RefCell, rc::Rc}; + +use crate::interlude::*; + +use deno_core::OpState; +// necessary for re-exported macros to work +#[rustfmt::skip] +use deno_core as deno_core; +use tokio::sync::{mpsc, oneshot}; + +use super::ExtConfig; +use super::ExtContext; + +#[derive(Debug, thiserror::Error)] +pub enum CallbackError { + #[error("no callback found under {key}")] + NotFound { key: String }, + #[error("callback protocol error")] + ProtocolError(#[source] eyre::Report), + #[error("error executing callback")] + JsError(#[source] eyre::Report), + #[error("v8 error")] + V8Error(#[source] eyre::Report), +} + +struct CallbackCtx { + msg_rx: mpsc::Receiver, + term_signal: tokio::sync::watch::Receiver, +} + +/// Line used by the callback_worker to receive +/// invocations. +#[derive(Default)] +pub struct CallbackLine { + /// This would be None if the callback line was already + /// taken or if the callback line was not initially set + cx: Option, + /// Indicates weather the callback line was initially set + was_set: bool, +} + +impl CallbackLine { + pub fn new(dworker: &denort::worker::DenoWorkerHandle) -> (Self, CallbacksHandle) { + let (msg_tx, msg_rx) = mpsc::channel(1); + ( + Self { + was_set: true, + cx: Some(CallbackCtx { + msg_rx, + term_signal: dworker.term_signal_watcher(), + }), + }, + CallbacksHandle { msg_tx }, + ) + } + + fn take(&mut self) -> Option { + if !self.was_set { + // debug!("callback line was not set, worker callbacks will noop"); + return None; + } + // debug!("realm with callbacks just had a child, it won't inherit callback feature"); + self.cx.take() + } +} + +/// Line used to invoke callbacks registered by js code. +#[derive(Clone)] +pub struct CallbacksHandle { + msg_tx: mpsc::Sender, +} + +impl CallbacksHandle { + pub async fn exec( + &self, + key: CHeapStr, + args: serde_json::Value, + ) -> Result { + let (tx, rx) = tokio::sync::oneshot::channel(); + self.msg_tx + .send(CallbacksMsg::Exec { + response_channel: tx, + key, + args, + }) + .await + .expect_or_log("channel error"); + rx.await.expect_or_log("channel error") + } +} + +/// Internal used to communicate between callback worker +#[derive(educe::Educe)] +#[educe(Debug)] +enum CallbacksMsg { + Exec { + #[educe(Debug(ignore))] + response_channel: oneshot::Sender>, + key: CHeapStr, + #[educe(Debug(ignore))] + args: serde_json::Value, + }, +} + +#[derive(Clone, Default)] +pub struct Callbacks { + store: Arc>, +} + +/// Start a worker task to execute callbacks on. +/// +/// Stored callbacks are not Sync so this expects to be started +/// on the same thread as deno. +/// This will return none if the callback line was set or +/// the callback line was already taken. This happens +/// with child WebWorkers for example which don't currently +/// support callbacks. +pub fn worker(config: &ExtConfig) -> Option { + let CallbackCtx { + msg_rx: mut rx, + term_signal, + } = { + let mut line = config.callbacks_rx.lock().expect_or_log("mutex err"); + line.take()? + }; + + let callbacks = Callbacks::default(); + let callbacks_2go = callbacks.clone(); + denort::unsync::spawn( + "callback-worker", + async move { + trace!("callback worker starting"); + while let Some(msg) = rx.recv().await { + trace!(?msg, "msg"); + match msg { + CallbacksMsg::Exec { + key: name, + args, + response_channel, + } => response_channel + .send( + callbacks_2go + .exec_callback(name, args, term_signal.clone()) + .await, + ) + .expect_or_log("channel error"), + } + } + trace!("callback worker done"); + } + .instrument(tracing::trace_span!("callback-worker")), + ); + Some(callbacks) +} + +impl Callbacks { + #[tracing::instrument(skip(self, args))] + pub async fn exec_callback( + &self, + key: CHeapStr, + args: serde_json::Value, + mut term_signal: tokio::sync::watch::Receiver, + ) -> Result { + let Some(cb) = self.store.get(&key[..]).map(|cb| cb.clone()) else { + return Err(CallbackError::NotFound { + key: key.to_string(), + }); + }; + + if *term_signal.borrow_and_update() { + trace!("callback invoked on terminated runtime"); + return Err(CallbackError::V8Error(ferr!("deno is shutting down"))); + } + + let (tx, rx) = oneshot::channel::>(); + + // we use the sender to spawn work on the v8 thread + let join_handle = tokio::task::spawn_blocking(move || { + cb.async_work_sender.spawn_blocking(move |scope| { + let args = serde_v8::to_v8(scope, args).map_err(|err| { + CallbackError::V8Error(ferr!(err).wrap_err("error serializaing args to v8")) + })?; + + let recv = v8::undefined(scope); + + let res = { + let tc_scope = &mut v8::TryCatch::new(scope); + // FIXME(@yohe): the original pointer was made from a global + // and yet we're transmuting it to a Local here. + // This is observed from the deno codebase + // and I can't explain it + // SAFETY: cargo culted from deno codebase + let func = unsafe { + std::mem::transmute::, v8::Local>( + cb.js_fn, + ) + }; + + let res = func + .call(tc_scope, recv.into(), &[args]) + // FIXME: under what circumstances can this be None? + .expect_or_log("got None from callback call"); + if tc_scope.has_caught() { + let exception = tc_scope.exception().unwrap(); + return Err(CallbackError::JsError( + ferr!(super::js_error_message(tc_scope, exception)) + .wrap_err("callback exception"), + )); + } + res + }; + if !res.is_promise() { + let res = serde_v8::from_v8(scope, res).map_err(|err| { + CallbackError::ProtocolError( + ferr!(err).wrap_err("error deserializaing result from v8"), + ) + })?; + return Ok(Some(res)); + } + let promise = v8::Local::::try_from(res).unwrap(); + let deno_shutting_down = + denort::promises::watch_promise(scope, promise, move |scope, _rf, res| { + let res = match res { + Ok(val) => serde_v8::from_v8(scope, val).map_err(|err| { + CallbackError::ProtocolError( + ferr!(err) + .wrap_err("error deserializaing promise result from v8"), + ) + }), + // FIXME: this is a bit of a mess and a bunch of workaround + // for private deno_core functionality as discussed at + // https://github.com/denoland/deno/discussions/27504 + Err(err) => Err(CallbackError::JsError( + ferr!(super::js_error_message(scope, err)) + .wrap_err("callback promise rejection"), + )), + }; + if let Err(res) = tx.send(res) { + debug!(?res, "callback response after abortion"); + } + }) + .is_none(); + if deno_shutting_down { + return Err(CallbackError::V8Error(ferr!("js runtime is shutting down"))); + }; + Ok(None) + }) + }); + + // if the callback is not async, we recieve the value right away + if let Some(res) = join_handle.await.expect_or_log("tokio error")? { + return Ok(res); + }; + + let res = tokio::select! { + _ = term_signal.wait_for(|signal| *signal) => { + trace!("callback worker recieved term signal"); + return Err(CallbackError::V8Error(ferr!("deno terminated waiting on callback"))); + }, + res = rx => { + res.expect_or_log("channel error")? + } + }; + + Ok(res) + } +} + +struct Callback { + js_fn: SendPtr, + async_work_sender: deno_core::V8CrossThreadTaskSpawner, +} + +impl Clone for Callback { + fn clone(&self) -> Self { + Self { + js_fn: SendPtr(self.js_fn.0), + async_work_sender: self.async_work_sender.clone(), + } + } +} + +#[derive(Clone, Copy)] +#[repr(transparent)] +struct SendPtr(std::ptr::NonNull); +// SAFETY: we only ever access this value from within the same thread +// as deno +unsafe impl Send for SendPtr {} + +#[tracing::instrument(skip(state, cb))] +#[deno_core::op2] +pub fn op_callbacks_set( + state: Rc>, + #[string] name: String, + #[global] cb: v8::Global, +) -> anyhow::Result<()> { + let (ctx, async_work_sender) = { + let state = state.borrow(); + let ctx = state.borrow::(); + let sender = state.borrow::(); + + (ctx.clone(), sender.clone()) + }; + let Some(callbacks) = ctx.callbacks else { + warn!("callback set but callback feature is not enabled"); + anyhow::bail!("callbacks feature is not enabled"); + }; + debug!(%name, "registering callback"); + callbacks.store.insert( + name.into(), + Callback { + js_fn: SendPtr(cb.into_raw()), + async_work_sender, + }, + ); + Ok(()) +} diff --git a/src/ghjk/host.rs b/src/ghjk/host.rs new file mode 100644 index 00000000..4cbcb10e --- /dev/null +++ b/src/ghjk/host.rs @@ -0,0 +1,378 @@ +use std::io::IsTerminal; + +use crate::interlude::*; + +use crate::systems::*; + +mod deno; +mod hashfile; + +use hashfile::HashObj; + +#[derive(Debug)] +pub struct Config { + /// Discard serialization cache. + pub re_serialize: bool, + /// Discard any resolved values in lockfile. + #[allow(unused)] + pub re_resolve: bool, + /// Force use serialization cache. + pub locked: bool, + pub env_vars: IndexMap, + pub cwd: PathBuf, +} + +#[derive(educe::Educe)] +#[educe(Debug)] +pub struct HostCtx { + pub gcx: Arc, + pub config: Config, + #[educe(Debug(ignore))] + pub systems: HashMap, + // NOTE: only use this for hashfile usage which is invalidated and generated + // anew around the serialization process which is expected to take a reasonably + // short amount of time. Any code, like system impls, afterwards might take + // an unkown amount of time possibly making the hashes in this memo stale + pub file_hash_memo: DHashMap, +} + +impl HostCtx { + pub fn new( + gcx: Arc, + config: Config, + systems: HashMap, + ) -> Self { + Self { + gcx, + config, + systems, + file_hash_memo: default(), + } + } +} + +#[tracing::instrument(skip(hcx))] +pub async fn systems_from_ghjkfile( + hcx: Arc, + ghjkdir_path: &Path, +) -> Res> { + let (hashfile_path, lockfile_path) = ( + ghjkdir_path.join("hash.json"), + ghjkdir_path.join("lock.json"), + ); + + // read both files concurrently + let (hash_obj, lock_obj) = futures::join!( + HashObj::from_file(&hashfile_path), + LockObj::from_file(&lockfile_path), + ); + + // discard corrupt files if needed + let (mut hash_obj, mut lock_obj) = ( + match hash_obj { + Ok(val) => val, + Err(hashfile::HashfileError::Serialization(_)) => { + error!("hashfile is corrupt, discarding"); + None + } + Err(hashfile::HashfileError::Other(err)) => return Err(err), + }, + match lock_obj { + Ok(val) => val, + Err(LockfileError::Serialization(err)) => { + // interactive discard of lockfile if in an interactive shell + if std::io::stderr().is_terminal() + && tokio::task::spawn_blocking(|| { + dialoguer::Confirm::new() + .with_prompt("lockfile is corrupt, discard?") + .default(false) + .interact() + }) + .await + .expect_or_log("tokio error") + .wrap_err("prompt error")? + { + None + } else { + return Err(ferr!(err).wrap_err("corrupt lockfile")); + } + } + Err(LockfileError::Other(err)) => return Err(err), + }, + ); + + if hcx.config.locked { + if hash_obj.is_none() { + eyre::bail!("locked flag is set but no hashfile found"); + } + if lock_obj.is_none() { + eyre::bail!("locked flag is set but no lockfile found"); + } + } + + let (ghjkfile_exists, ghjkfile_hash) = if let Some(path) = &hcx.gcx.config.ghjkfile { + ( + matches!(tokio::fs::try_exists(path).await, Ok(true)), + Some( + hashfile::file_digest_hash(hcx.as_ref(), path) + .await? + .unwrap(), + ), + ) + } else { + (false, None) + }; + + // check if we need to discard the hashfile + if let Some(obj) = &mut hash_obj { + // NOTE: version migrator would go here + if obj.version != "0" { + eyre::bail!("unsupported hashfile version: {:?}", obj.version); + } + if !hcx.config.locked + && (hcx.config.re_serialize + // no need for expensive staleness checks if the ghjkfile + // no longer exists + || ghjkfile_hash.is_none() + || obj + .is_stale(hcx.as_ref()) + .await + .inspect(|is_stale| { + if *is_stale { + debug!("stale hashfile, discarding") + } + })?) + { + hash_obj = None; + } + } + // check if we need to discard the lockfile + if let Some(obj) = &mut lock_obj { + // TODO: version migrator + if obj.version != "0" { + eyre::bail!("unsupported hashfile version: {:?}", obj.version); + } + } + // TODO: + // if hcx.re_resolve {} + + let mut lock_entries = HashMap::new(); + + if let Some(lock_obj) = &mut lock_obj { + debug!(?lockfile_path, "loading lockfile"); + for sys_conf in &lock_obj.config.modules { + let Some(sys_man) = hcx.systems.get(&sys_conf.id) else { + eyre::bail!( + "unrecognized system found in lockfile config: {:?}", + sys_conf.id + ); + }; + let Some(sys_lock) = lock_obj.sys_entries.swap_remove(&sys_conf.id) else { + eyre::bail!( + "no lock entry found for system specified by lockfile config: {:?}", + sys_conf.id + ); + }; + let sys_inst = sys_man.init().await?; + lock_entries.insert( + sys_conf.id.clone(), + sys_inst.load_lock_entry(sys_lock).await?, + ); + } + } + + let mut fresh_serialized = false; + + let (config, hash_obj) = if let (Some(lock_obj), Some(hash_obj)) = (&lock_obj, hash_obj) { + // Only recover the old config if the hash_obj and lock_obj haven't + // been discarded by the cache invalidation checks above. + // Assumes that a hashfile tags the specific serialized version of the ghjkfile + // and it's context put in the lockfile + (lock_obj.config.clone(), hash_obj) + } else if let Some(ghjkfile_path) = &hcx.gcx.config.ghjkfile { + if !ghjkfile_exists { + eyre::bail!("no file found at ghjkfile path {ghjkfile_path:?}"); + } + if hcx.config.locked { + unreachable!("code should have early exited"); + } + info!(?ghjkfile_path, "serializing ghjkfile"); + fresh_serialized = true; + // TODO: configurable timeout on serialization + serialize_ghjkfile(hcx.as_ref(), ghjkfile_path) + .await + .wrap_err("error serializing ghjkfile")? + } else { + if hcx.config.locked { + unreachable!("code should have early exited"); + } + return Ok(None); + }; + + debug!("initializing ghjkfile systems"); + let sys_instances = { + let mut sys_instances = IndexMap::new(); + for sys_conf in &config.modules { + let Some(sys_man) = hcx.systems.get(&sys_conf.id) else { + eyre::bail!( + "unrecognized system specified by ghjkfile: {:?}", + sys_conf.id + ); + }; + let sys_inst = sys_man.init().await?; + sys_inst + .load_config( + sys_conf.config.clone(), + config.blackboard.clone(), + lock_entries.remove(&sys_conf.id), + ) + .await + .wrap_err_with(|| format!("error loading system config: {:?}", sys_conf.id))?; + sys_instances.insert(sys_conf.id.clone(), sys_inst); + } + sys_instances + }; + + Ok(Some(GhjkfileSystems { + hcx, + config, + sys_instances, + hash_obj, + old_lock_obj: lock_obj, + lockfile_path, + hashfile_path, + fresh_serialized, + hashfile_written: false, + })) +} + +pub struct GhjkfileSystems { + hcx: Arc, + pub config: Arc, + hash_obj: HashObj, + pub sys_instances: IndexMap, + old_lock_obj: Option, + lockfile_path: PathBuf, + hashfile_path: PathBuf, + fresh_serialized: bool, + hashfile_written: bool, +} + +impl GhjkfileSystems { + pub async fn write_lockfile_or_log(&mut self) { + if let Err(err) = self.write_lockfile().await { + error!("error writing lockfile: {err}"); + } + } + + #[tracing::instrument(skip(self))] + pub async fn write_lockfile(&mut self) -> Res<()> { + let mut lock_obj = LockObj { + version: "0".into(), + config: self.config.clone(), + sys_entries: default(), + }; + // generate the lock entries after *all* the systems + // are done processing their config to allow + // any shared stores to be properly populated + // e.g. the resolution memo store + for (sys_id, sys_inst) in &mut self.sys_instances { + let lock_entry = sys_inst.gen_lock_entry().await.wrap_err_with(|| { + format!("error generating lock entry for system: {:?}", sys_id) + })?; + lock_obj.sys_entries.insert(sys_id.clone(), lock_entry); + } + + if self.old_lock_obj.is_none() + || matches!(self.old_lock_obj.as_ref(), Some(old) if !old.eq(&lock_obj)) + { + if self.hcx.config.locked { + warn!("locked flag set, changes to lockfile discarded"); + } else { + trace!(lockfile_path = ?self.lockfile_path, /* ?lock_obj, */ "writing lock.json"); + tokio::fs::write( + &self.lockfile_path, + serde_json::to_vec_pretty(&lock_obj).expect_or_log("error jsonifying lockfile"), + ) + .await + .wrap_err("error writing to lockfile")?; + self.old_lock_obj.replace(lock_obj); + } + } + + // Only write out hashfile when a fresh serialization + // result was saved in the lock file. + if self.fresh_serialized && !self.hashfile_written { + if self.hcx.config.locked { + unreachable!("code should have early exited"); + } + trace!(hashfile_path = ?self.hashfile_path, /* hash_obj= ?self.hash_obj, */ "writing hash.json"); + tokio::fs::write( + &self.hashfile_path, + serde_json::to_vec_pretty(&self.hash_obj) + .expect_or_log("error jsonifying hashfile"), + ) + .await + .wrap_err("error writing to lockfile")?; + self.hashfile_written = true; + } + Ok(()) + } +} + +async fn serialize_ghjkfile(hcx: &HostCtx, path: &Path) -> Res<(Arc, HashObj)> { + let ext = path.extension(); + let res = if ext.map(|ext| ext == "ts" || ext == "js") == Some(true) { + deno::serialize_deno_ghjkfile(hcx, path).await? + } else { + eyre::bail!("unrecognized ghjkfile extension: {path:?}") + }; + debug!("ghjkfile serialized"); + let hash_obj = HashObj::from_result(hcx, path, &res) + .await + .wrap_err("error building hash obj")?; + Ok((Arc::new(res.config), hash_obj)) +} + +#[derive(Debug)] +struct SerializationResult { + config: SerializedConfig, + accessed_env_keys: Vec, + read_file_paths: Vec, + listed_file_paths: Vec, +} + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +pub struct SerializedConfig { + modules: Vec, + blackboard: ConfigBlackboard, +} + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +pub struct LockObj { + pub version: String, + pub sys_entries: indexmap::IndexMap, + pub config: Arc, +} + +#[derive(Debug, thiserror::Error)] +pub enum LockfileError { + #[error("error parsing lockfile:{0}")] + Serialization(serde_json::Error), + #[error(transparent)] + Other(#[from] eyre::Report), +} + +impl LockObj { + /// The lock.json file stores the serialized config and some entries + /// from systems. It's primary purpose is as a memo store to avoid + /// re-serialization on each CLI invocation. + pub async fn from_file(path: &Path) -> Result, LockfileError> { + let raw = match tokio::fs::read(path).await { + Ok(val) => val, + Err(err) if err.kind() == std::io::ErrorKind::NotFound => return Ok(None), + Err(err) => return Err(LockfileError::Other(ferr!("error reading hashfile: {err}"))), + }; + serde_json::from_slice(&raw).map_err(LockfileError::Serialization) + } +} diff --git a/src/ghjk/host/deno.rs b/src/ghjk/host/deno.rs new file mode 100644 index 00000000..35bbdbd2 --- /dev/null +++ b/src/ghjk/host/deno.rs @@ -0,0 +1,92 @@ +use crate::interlude::*; + +use denort::deno::deno_runtime; + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct InternalSerializationResult { + config: super::SerializedConfig, + accessed_env_keys: Vec, + read_file_paths: Vec, + listed_file_paths: Vec, +} + +#[tracing::instrument(skip(hcx))] +pub async fn serialize_deno_ghjkfile( + hcx: &super::HostCtx, + path: &Path, +) -> Res { + let main_module = hcx + .gcx + .config + .repo_root + .join("files/deno/bindings.ts") + .wrap_err("repo url error")?; + + let mut ext_conf = crate::ext::ExtConfig::new(); + + ext_conf.blackboard = [ + // blackboard is used as communication means + // with the deno side of the code + ( + "args".into(), + json!({ + "uri": url::Url::from_file_path(path).unwrap_or_log(), + }), + ), + ] + .into_iter() + .collect::>() + .into(); + + let bb = ext_conf.blackboard.clone(); + + let worker = hcx + .gcx + .deno + .prepare_module( + main_module.clone(), + deno_runtime::deno_permissions::PermissionsOptions { + allow_env: Some(vec![]), + allow_import: Some(vec![]), + allow_read: Some(vec![]), + allow_net: Some(vec![]), + ..default() + }, + deno_runtime::WorkerExecutionMode::Run, + default(), + Some(crate::ext::extensions(ext_conf)), + ) + .await?; + + let (exit_code, mut worker) = worker.run().await?; + if exit_code != 0 { + eyre::bail!("non-zero exit code running deno module"); + } + let loaded_modules = worker.get_loaded_modules().await; + + let (_, resp) = bb.remove("resp").expect_or_log("resp missing"); + let resp: InternalSerializationResult = + serde_json::from_value(resp).expect_or_log("error deserializing resp"); + + let mut loaded_modules = loaded_modules + .into_iter() + .filter(|url| url.scheme() == "file") + .map(|url| { + url.to_file_path() + .map_err(|()| ferr!("url to path error: {url}")) + }) + .collect::>>()?; + + let mut read_file_paths = resp.read_file_paths; + read_file_paths.append(&mut loaded_modules); + + debug!("ghjk.ts serialized"); + + Ok(super::SerializationResult { + config: resp.config, + accessed_env_keys: resp.accessed_env_keys, + listed_file_paths: resp.listed_file_paths, + read_file_paths, + }) +} diff --git a/src/ghjk/host/hashfile.rs b/src/ghjk/host/hashfile.rs new file mode 100644 index 00000000..5ec14e02 --- /dev/null +++ b/src/ghjk/host/hashfile.rs @@ -0,0 +1,271 @@ +use crate::interlude::*; + +use super::HostCtx; + +#[derive(Debug, Serialize, Deserialize)] +pub struct HashObj { + pub version: String, + /// Hashes of all env vars that were read. + pub env_var_hashes: indexmap::IndexMap>, + /// Hashes of all files that were read. + pub read_file_hashes: indexmap::IndexMap>, + /// File paths that were observed from the fs but not necessarily + /// read. + pub listed_files: Vec, +} + +#[derive(Debug, thiserror::Error)] +pub enum HashfileError { + #[error("error parsing hashfile: {0}")] + Serialization(serde_json::Error), + #[error("{0}")] + Other(#[source] eyre::Report), +} + +impl HashObj { + #[tracing::instrument(skip(hcx, res))] + pub async fn from_result( + hcx: &super::HostCtx, + ghjkfile_path: &Path, + res: &super::SerializationResult, + ) -> Res { + Ok(HashObj { + version: "0".into(), + env_var_hashes: env_var_digests( + &hcx.config.env_vars, + res.accessed_env_keys.iter().map(|key| key.as_ref()), + ), + listed_files: res + .listed_file_paths + .iter() + .map(|path| { + pathdiff::diff_paths( + std::path::absolute(path).expect_or_log("error absolutizing path"), + &hcx.config.cwd, + ) + .unwrap_or_log() + }) + .collect(), + read_file_hashes: file_digests( + hcx, + res.read_file_paths + .iter() + .map(|path| path.as_ref()) + .collect(), + ) + .await?, + }) + } + + /// The hash.json file stores the digests of all external accesses + /// of a ghjkfile during serialization. The primary purpose is to + /// do "cache invalidation" on ghjkfiles, re-serializing them if + /// any of the digests change. + pub async fn from_file(path: &Path) -> Result, HashfileError> { + let raw = match tokio::fs::read(path).await { + Ok(val) => val, + Err(err) if err.kind() == std::io::ErrorKind::NotFound => return Ok(None), + Err(err) => return Err(HashfileError::Other(ferr!("error reading hashfile: {err}"))), + }; + serde_json::from_slice(&raw).map_err(HashfileError::Serialization) + } + + #[tracing::instrument(skip(hcx))] + pub async fn is_stale(&self, hcx: &HostCtx) -> Res { + { + let new_digest = env_var_digests( + &hcx.config.env_vars, + self.env_var_hashes.keys().map(|key| &key[..]), + ); + if self.env_var_hashes != new_digest { + trace!("stale env var digests"); + return Ok(true); + } + } + { + for path in &self.listed_files { + if !matches!(tokio::fs::try_exists(path).await, Ok(true)) { + trace!("stale listed files"); + return Ok(true); + } + } + } + { + if self.read_file_hashes + != file_digests( + hcx, + self.read_file_hashes + .keys() + .map(|path| path.as_ref()) + .collect(), + ) + .await? + { + trace!("stale read files digest"); + return Ok(true); + } + } + Ok(false) + } +} + +fn env_var_digests<'a>( + all: &IndexMap, + accessed: impl Iterator, +) -> IndexMap> { + accessed + .map(|key| { + ( + key.to_owned(), + all.get(key).map(|val| crate::utils::hash_str(val)), + ) + }) + .collect() +} + +async fn file_digests( + hcx: &HostCtx, + read_files: Vec<&Path>, +) -> Res>> { + use futures::StreamExt; + let mut map = futures::stream::iter(read_files.into_iter().map(|path| { + async move { + let path = std::path::absolute(path)?; + let hash = file_digest_hash(hcx, &path).await?; + let relative_path = pathdiff::diff_paths(path, &hcx.config.cwd).unwrap(); + Ok((relative_path, hash)) + } + .boxed() + })) + .buffer_unordered(16) + .collect::>() + .await + .into_iter() + .collect::>>()?; + map.sort_unstable_keys(); + Ok(map) +} + +#[tracing::instrument(skip(hcx))] +pub async fn file_digest_hash(hcx: &HostCtx, path: &Path) -> Res> { + let path = match tokio::fs::canonicalize(path).await { + Ok(val) => val, + Err(err) if err.kind() == std::io::ErrorKind::NotFound => { + return Ok(None); + } + Err(err) => return Err(err).wrap_err("error resolving realpath"), + }; + match tokio::fs::metadata(&path).await { + Ok(stat) => { + const LARGE_FILE_THRESHOLD: u64 = 100 * 1024 * 1024; // 100MB + + let content_hash = if stat.file_type().is_file() || stat.file_type().is_symlink() { + if stat.len() > LARGE_FILE_THRESHOLD { + warn!( + len = stat.len(), + "large file detected, skippin content hash" + ); + None + } else { + Some( + file_content_digest_hash(hcx, &path) + .await? + .await + .map_err(|err| ferr!(err))?, + ) + } + } else { + None + }; + + let stat = StatMeta { + // we're not going to invalidate on access + accessed: None, + ..StatMeta::from(stat) + }; + let json = json!({ + "content_hash": content_hash, + "stat": stat + }); + Ok(Some(crate::utils::hash_obj(&json))) + } + Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(None), + Err(err) => Err(err).wrap_err("error on file stat"), + } +} + +pub type SharedFileContentDigestFuture = + futures::future::Shared>>; + +async fn file_content_digest_hash( + hcx: &HostCtx, + path: &Path, +) -> Res { + let path = path.to_owned(); + use dashmap::mapref::entry::*; + match hcx.file_hash_memo.entry(path.clone()) { + Entry::Occupied(occupied_entry) => Ok(occupied_entry.get().clone()), + Entry::Vacant(vacant_entry) => { + let shared = vacant_entry + .insert( + async { + let file = tokio::fs::File::open(path) + .await + .map_err(|err| format!("error opening file: {err}"))?; + let hash: CHeapStr = crate::utils::hash_reader(file) + .await + .map_err(|err| format!("error hashing file reader {err}"))? + .into(); + Ok(hash) + } + .boxed() + .shared(), + ) + .value() + .clone(); + Ok(shared) + } + } +} + +#[derive(Serialize)] +struct StatMeta { + accessed: Option, + created: Option, + modified: Option, + is_file: bool, + is_dir: bool, + is_symlink: bool, + size: u64, + #[cfg(unix)] + mode: u32, +} + +impl From for StatMeta { + fn from(value: std::fs::Metadata) -> Self { + fn unwrap_opt_sys_time(inp: std::io::Result) -> Option { + inp.map_err(|_| ()) + .and_then(|ts| { + ts.duration_since(std::time::SystemTime::UNIX_EPOCH) + .map_err(|_| ()) + }) + .map(|dur| dur.as_secs()) + .ok() + } + #[cfg(unix)] + use std::os::unix::fs::PermissionsExt; + + Self { + // file_type: match value.file_type() {}, + accessed: unwrap_opt_sys_time(value.accessed()), + created: unwrap_opt_sys_time(value.created()), + modified: unwrap_opt_sys_time(value.modified()), + is_file: value.is_file(), + is_symlink: value.is_symlink(), + is_dir: value.is_dir(), + size: value.len(), + #[cfg(unix)] + mode: value.permissions().mode(), + } + } +} diff --git a/src/ghjk/js/00_runtime.js b/src/ghjk/js/00_runtime.js new file mode 100644 index 00000000..2870e5d2 --- /dev/null +++ b/src/ghjk/js/00_runtime.js @@ -0,0 +1,44 @@ +// const { core } = Deno[Deno.internal]; +const { core } = Deno; +const { ops } = core; +// const fastops = core.ensureFastOps(); // TODO: investigate + +// NOTE: use the following import if ever switching to snaphsots +// import * as ops from "ext:core/ops"; + +function getOp(name) { + // Note: always get the op right away. + // the core.ops object is a proxy + // that retrieves the named op + // when requested i.e. not a + // hashmap prepopulated by the ops. + // If we don't get the op now, the + // proxy behvior won't be avail later at runtime + const op = ops[name]; + if (!op) { + throw Error(`op: ${name} not found`); + } + return op; +} + +const op_callbacks_set = getOp("op_callbacks_set"); + +/** + * @type {import('./runtime.d.ts').GhjkNs} + */ +const ____GhjkHost = { + blackboard: { + get: getOp("op_blackboard_get"), + set: getOp("op_blackboard_set"), + }, + callbacks: { + set: (key, fn) => { + op_callbacks_set(key, fn); + return key; + }, + }, + hostcall: getOp("op_hostcall"), + dispatchException: getOp("op_dispatch_exception2"), +}; + +globalThis.____GhjkHost = ____GhjkHost; diff --git a/src/ghjk/js/mock.sfx.ts b/src/ghjk/js/mock.sfx.ts new file mode 100644 index 00000000..76de8147 --- /dev/null +++ b/src/ghjk/js/mock.sfx.ts @@ -0,0 +1,20 @@ +//! Import this as a side effect for a mock the Ghjk object. +//! Useful to sanity check code that relies on the Ghjk extension. + +import { Ghjk } from "./runtime.js"; + +const bb = new Map(); +Object.assign(Ghjk, { + callbacks: { + set: (key: string) => key, + }, + hostcall: () => Promise.resolve({}), + blackboard: { + set: (key: string, value: any) => { + const old = bb.get(key); + bb.set(key, value); + return old; + }, + get: (key: string) => bb.get(key), + }, +}); diff --git a/src/ghjk/js/runtime.d.ts b/src/ghjk/js/runtime.d.ts new file mode 100644 index 00000000..d0bc53ec --- /dev/null +++ b/src/ghjk/js/runtime.d.ts @@ -0,0 +1,17 @@ +export type JsonLiteral = string | number | boolean | null; +export type JsonObject = { [key: string]: Json }; +export type JsonArray = Json[]; +export type Json = JsonLiteral | JsonObject | JsonArray; + +type GhjkNs = { + blackboard: { + get: (key: string) => Json | undefined; + set: (key: string, value: Json) => Json | undefined; + }; + callbacks: { + set: (key: string, fn: (arg: Json) => Json | Promise) => string; + }; + hostcall: (key: string, args: Json) => Promise; + dispatchException: (exception: any) => boolean; +}; +export const Ghjk: GhjkNs; diff --git a/src/ghjk/js/runtime.js b/src/ghjk/js/runtime.js new file mode 100644 index 00000000..2931f835 --- /dev/null +++ b/src/ghjk/js/runtime.js @@ -0,0 +1,10 @@ +/// + +//! This file provides the import point for types and values defined in: +// - ./00_runtime.js: which is preloaded by the custom deno runtime +// - ./runtime.d.ts: which types the objects from the preload + +/** + * @type {import('./runtime.d.ts').GhjkNs} + */ +export const Ghjk = globalThis.____GhjkHost; diff --git a/src/ghjk/log.rs b/src/ghjk/log.rs new file mode 100644 index 00000000..5aba03c9 --- /dev/null +++ b/src/ghjk/log.rs @@ -0,0 +1,100 @@ +use crate::interlude::*; + +pub fn init() { + static INIT: std::sync::Once = std::sync::Once::new(); + INIT.call_once(|| { + let eyre_panic_hook = color_eyre::config::HookBuilder::default().display_location_section( + std::env::var("RUST_ERR_LOCATION") + .map(|var| var != "0") + .unwrap_or(true), + ); + + #[cfg(not(debug_assertions))] + let eyre_panic_hook = eyre_panic_hook.panic_section(format!( + r#"Ghjk has panicked. This is a bug, please report this +at https://github.com/metatypedev/ghjk/issues/new. +If you can reliably reproduce this panic, try to include the +following items in your report: +- Reproduction steps +- Output of meta-cli doctor and +- A panic backtrace. Set the following environment variables as shown to enable full backtraces. + - RUST_BACKTRACE=1 + - RUST_LIB_BACKTRACE=full + - RUST_SPANTRACE=1 +Platform: {platform} +Version: {version} +Args: {args:?} +"#, + platform = crate::shadow::BUILD_TARGET, + // TODO: include commit sha + version = crate::shadow::PKG_VERSION, + args = std::env::args().collect::>() + )); + + let (eyre_panic_hook, _eyre_hook) = eyre_panic_hook.try_into_hooks().unwrap(); + let eyre_panic_hook = eyre_panic_hook.into_panic_hook(); + + std::panic::set_hook(Box::new(move |panic_info| { + if let Some(msg) = panic_info + .payload() + .downcast_ref::() + .map(|val| val.as_str()) + .or_else(|| panic_info.payload().downcast_ref::<&str>().cloned()) + { + if msg.contains("A Tokio 1.x context was found, but it is being shutdown.") { + warn!("improper shutdown, make sure to terminate all workers first"); + return; + } + } + eyre_panic_hook(panic_info); + // - Tokio does not exit the process when a task panics, so we define a custom + // panic hook to implement this behaviour. + // std::process::exit(1); + })); + + _eyre_hook.install().unwrap(); + + if std::env::var("RUST_LOG").is_err() { + std::env::set_var("RUST_LOG", "info"); + } + #[cfg(not(debug_assertions))] + if std::env::var("RUST_SPANTRACE").is_err() { + std::env::set_var("RUST_SPANTRACE", "0"); + } + + use tracing_subscriber::prelude::*; + + let fmt = tracing_subscriber::fmt::layer() + .without_time() + .with_writer(std::io::stderr) + // .pretty() + // .with_file(true) + // .with_line_number(true) + .with_target(false); + + #[cfg(test)] + let fmt = fmt.with_test_writer(); + + #[cfg(debug_assertions)] + let fmt = fmt.with_target(true); + + let filter = tracing_subscriber::EnvFilter::from_default_env(); + + let registry = tracing_subscriber::registry(); + + #[cfg(feature = "console-subscriber")] + // FIXME: this isn't being picked up by tokio-console + let registry = registry.with(console_subscriber::spawn()); + + let registry = registry + // filter on values from RUST_LOG + .with(filter) + // subscriber that emits to stderr + .with(fmt) + // instrument errors with SpanTraces, used by color-eyre + .with(tracing_error::ErrorLayer::default()); + + registry.init(); + // console_subscriber::init(); + }); +} diff --git a/src/ghjk/main.rs b/src/ghjk/main.rs new file mode 100644 index 00000000..f8324dd6 --- /dev/null +++ b/src/ghjk/main.rs @@ -0,0 +1,72 @@ +#[allow(unused)] +mod interlude { + pub use crate::utils::{default, CHeapStr, DHashMap}; + + pub use std::collections::HashMap; + pub use std::path::{Path, PathBuf}; + pub use std::sync::Arc; + + pub use crate::GhjkCtx; + + pub use color_eyre::eyre; + pub use denort::deno::{ + self, + deno_runtime::{ + self, + deno_core::{self, serde_v8, url, v8}, + }, + }; + pub use eyre::{format_err as ferr, Context, Result as Res, WrapErr}; + pub use futures::{future::BoxFuture, FutureExt}; + pub use indexmap::IndexMap; + pub use serde::{Deserialize, Serialize}; + pub use serde_json::json; + pub use smallvec::smallvec as svec; + pub use smallvec::SmallVec as Svec; + pub use tracing::{debug, error, info, trace, warn, Instrument}; + pub use tracing_unwrap::*; +} + +mod host; + +mod cli; +mod config; +mod ext; +mod log; +mod systems; +mod utils; + +use crate::interlude::*; + +fn main() -> Res { + let None = cli::deno_quick_cli() else { + unreachable!(); + }; + + // FIXME: change signal handler for children + // FIXME: use unix_sigpipe once https://github.com/rust-lang/rust/issues/97889 lands + unsafe { + use nix::sys::signal::*; + signal(Signal::SIGPIPE, SigHandler::SigDfl)?; + } + std::env::set_var("DENO_NO_UPDATE_CHECK", "1"); + + log::init(); + denort::init(); + + debug!(version = shadow::PKG_VERSION, "ghjk CLI"); + + tokio::runtime::Builder::new_current_thread() + .enable_all() + .build()? + .block_on(cli::cli()) +} + +use shadow_rs::shadow; +shadow!(shadow); + +#[derive(Debug)] +pub struct GhjkCtx { + deno: denort::worker::DenoWorkerHandle, + config: config::Config, +} diff --git a/src/ghjk/systems.rs b/src/ghjk/systems.rs new file mode 100644 index 00000000..c0b34f14 --- /dev/null +++ b/src/ghjk/systems.rs @@ -0,0 +1,149 @@ +//! Systems (formerly modules) are units of implementation that bundle together +//! related functionality. + +use std::any::Any; + +use crate::interlude::*; + +pub mod deno; + +pub enum SystemManifest { + Deno(deno::DenoSystemManifest), +} + +impl SystemManifest { + pub async fn init(&self) -> Res { + match self { + SystemManifest::Deno(man) => Ok(ErasedSystemInstance::new(Arc::new(man.ctor().await?))), + } + } +} + +#[async_trait::async_trait] +pub trait SystemInstance { + type LockState; + + async fn load_config( + &self, + config: serde_json::Value, + bb: ConfigBlackboard, + state: Option, + ) -> Res<()>; + + async fn load_lock_entry(&self, raw: serde_json::Value) -> Res; + + async fn gen_lock_entry(&self) -> Res; + + async fn commands(&self) -> Res>; +} + +type BoxAny = Box; + +#[allow(clippy::type_complexity)] +pub struct ErasedSystemInstance { + load_lock_entry_fn: Box BoxFuture<'static, Res>>, + gen_lock_entry_fn: Box BoxFuture<'static, Res>>, + load_config_fn: Box< + dyn Fn(serde_json::Value, ConfigBlackboard, Option) -> BoxFuture<'static, Res<()>>, + >, + commands_fn: Box BoxFuture<'static, Res>>>, +} + +impl ErasedSystemInstance { + pub fn new(instance: Arc) -> Self + where + S: SystemInstance + Send + Sync + 'static, + L: std::any::Any + Send + Sync, + { + Self { + load_lock_entry_fn: { + let instance = instance.clone(); + Box::new(move |raw| { + let instance = instance.clone(); + async move { + let res: BoxAny = Box::new(instance.load_lock_entry(raw).await?); + Ok(res) + } + .boxed() + }) + }, + gen_lock_entry_fn: { + let instance = instance.clone(); + Box::new(move || { + let instance = instance.clone(); + async move { instance.gen_lock_entry().await }.boxed() + }) + }, + load_config_fn: { + let instance = instance.clone(); + Box::new(move |config, bb, state| { + let instance = instance.clone(); + async move { + let state: Option> = + state.map(|st| st.downcast().expect_or_log("downcast error")); + instance.load_config(config, bb, state.map(|bx| *bx)).await + } + .boxed() + }) + }, + commands_fn: { + let instance = instance.clone(); + Box::new(move || { + let instance = instance.clone(); + async move { instance.commands().await }.boxed() + }) + }, + } + } + + pub async fn load_config( + &self, + config: serde_json::Value, + bb: ConfigBlackboard, + state: Option, + ) -> Res<()> { + (self.load_config_fn)(config, bb, state).await + } + + pub async fn load_lock_entry(&self, raw: serde_json::Value) -> Res { + (self.load_lock_entry_fn)(raw).await + } + + pub async fn gen_lock_entry(&self) -> Res { + (self.gen_lock_entry_fn)().await + } + + pub async fn commands(&self) -> Res> { + (self.commands_fn)().await + } +} + +pub type SystemId = CHeapStr; + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +pub struct SystemConfig { + pub id: SystemId, + pub config: serde_json::Value, +} + +pub type CliCommandAction = + Box BoxFuture<'static, Res<()>> + Send + Sync>; + +pub struct SystemCliCommand { + pub name: CHeapStr, + pub clap: clap::Command, + pub sub_commands: IndexMap, + pub action: Option, +} + +impl std::fmt::Debug for SystemCliCommand { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("SystemCliCommand") + .field("name", &self.name) + .field("sub_commands", &self.sub_commands) + .field("actions", &self.action.is_some()) + .finish() + } +} + +pub type ConfigBlackboard = Arc>; diff --git a/src/ghjk/systems/deno.rs b/src/ghjk/systems/deno.rs new file mode 100644 index 00000000..bee5aa85 --- /dev/null +++ b/src/ghjk/systems/deno.rs @@ -0,0 +1,321 @@ +//! This module implements support for systems written in typescript +//! running on top of deno. + +use crate::interlude::*; + +use super::{SystemCliCommand, SystemId, SystemInstance, SystemManifest}; + +mod cli; + +#[derive(Clone)] +pub struct DenoSystemsContext { + callbacks: crate::ext::CallbacksHandle, + exit_code_channel: Arc>>>>, + term_signal: tokio::sync::watch::Sender, + #[allow(unused)] + hostcalls: crate::ext::Hostcalls, +} + +impl DenoSystemsContext { + #[allow(unused)] + pub async fn terminate(mut self) -> Res<()> { + let channel = { + let mut opt = self.exit_code_channel.lock().expect_or_log("mutex error"); + opt.take() + }; + let Some(channel) = channel else { + eyre::bail!("already terminated") + }; + self.term_signal.send(true).expect_or_log("channel error"); + channel.await.expect_or_log("channel error") + } +} + +#[tracing::instrument(skip(gcx))] +pub async fn systems_from_deno( + gcx: &GhjkCtx, + source_uri: &url::Url, + ghjkdir_path: &Path, +) -> Res<(HashMap, DenoSystemsContext)> { + let main_module = gcx + .config + .repo_root + .join("src/deno_systems/bindings.ts") + .wrap_err("repo url error")?; + + let mut ext_conf = crate::ext::ExtConfig::new(); + + let bb = ext_conf.blackboard.clone(); + bb.insert("args".into(), { + #[derive(Serialize)] + struct ConfigRef<'a> { + pub ghjkfile: Option<&'a Path>, + pub ghjkdir: &'a Path, + pub data_dir: &'a Path, + pub deno_dir: &'a Path, + pub deno_lockfile: Option<&'a Path>, + pub repo_root: &'a url::Url, + } + + #[derive(Serialize)] + struct BindingArgs<'a> { + uri: url::Url, + config: ConfigRef<'a>, + } + let crate::config::Config { + repo_root, + ghjkdir: _, + data_dir, + deno_lockfile, + ghjkfile, + deno_dir, + } = &gcx.config; + + json!(BindingArgs { + uri: source_uri.clone(), + config: ConfigRef { + ghjkfile: ghjkfile.as_ref().map(|path| path.as_path()), + ghjkdir: ghjkdir_path, + data_dir, + deno_lockfile: deno_lockfile.as_ref().map(|path| path.as_path()), + deno_dir, + repo_root + }, + }) + }); + let hostcalls = ext_conf.hostcalls.clone(); + + let (manifests_tx, mut manifests_rx) = tokio::sync::mpsc::channel(1); + hostcalls.funcs.insert( + "register_systems".into(), + Box::new(move |args| { + let tx = manifests_tx.clone(); + async move { + tx.send(args).await.expect_or_log("channel error"); + Ok(serde_json::Value::Null) + } + .boxed() + }), + ); + let cb_line = ext_conf.callbacks_handle(&gcx.deno); + let mut exception_line = ext_conf.exceptions_rx(); + + let mut worker = gcx + .deno + .prepare_module( + main_module, + deno_runtime::deno_permissions::PermissionsOptions { + allow_env: Some(vec![]), + allow_import: Some(vec![]), + allow_read: Some(vec![]), + allow_net: Some(vec![]), + allow_ffi: Some(vec![]), + allow_run: Some(vec![]), + allow_sys: Some(vec![]), + allow_write: Some(vec![]), + allow_all: true, + prompt: false, + ..default() + }, + deno_runtime::WorkerExecutionMode::Run, + default(), + Some(crate::ext::extensions(ext_conf)), + ) + .await?; + worker.execute().await?; + let mut active_worker = worker.drive_till_exit().await?; + + let manifests = tokio::select! { + res = &mut active_worker.exit_code_rx => { + let exit_code = res + .expect_or_log("channel error") + .wrap_err("deno systems error building manifests")?; + eyre::bail!("premature exit of deno systems before manifests were sent: exit code = {exit_code}"); + }, + manifests = manifests_rx.recv() => { + manifests.expect_or_log("channel error") + } + }; + + let manifests: Vec = + serde_json::from_value(manifests).wrap_err("protocol error")?; + + let term_signal = active_worker.term_signal_tx.clone(); + let join_exit_code_watcher = { + let dcx = gcx.deno.clone(); + tokio::spawn(async move { + let res; + loop { + res = tokio::select! { + res = &mut active_worker.exit_code_rx => { + match res { + Ok(res) => res.wrap_err("error on deno worker for deno systems"), + Err(_) => Err(ferr!("deno systems unexpected shutdown")) + } + } + Some(err) = exception_line.recv() => { + // NOTE: we only log the error here + // this assumes that the systems are processing + // a callback and that they will recieve an EventError + // when the event loop continues + // mostly relevant for Worker errors + error!("event loop error caught: {err}"); + continue; + } + }; + break; + } + let err = match res { + Ok(0) => return Ok(()), + Ok(exit_code) => { + ferr!("deno systems died with non-zero exit code: {exit_code}") + } + Err(err) => err, + }; + error!("deno systems error: {err:?}"); + dcx.terminate() + .await + .expect_or_log("error terminating deno worker"); + Err(err) + }) + }; + + let exit_code_channel = Arc::new(std::sync::Mutex::new(Some(join_exit_code_watcher))); + + let scx = DenoSystemsContext { + callbacks: cb_line, + hostcalls, + term_signal, + exit_code_channel, + }; + + let manifests = manifests + .into_iter() + .map(|desc| { + ( + desc.id.clone(), + SystemManifest::Deno(DenoSystemManifest { + desc, + scx: scx.clone(), + }), + ) + }) + .collect(); + + Ok((manifests, scx)) +} + +#[derive(Debug, Deserialize)] +struct ManifestDesc { + id: SystemId, + ctor_cb_key: CHeapStr, +} + +#[derive(educe::Educe)] +#[educe(Debug)] +pub struct DenoSystemManifest { + desc: ManifestDesc, + #[educe(Debug(ignore))] + scx: DenoSystemsContext, +} + +impl DenoSystemManifest { + #[tracing::instrument] + pub async fn ctor(&self) -> Res { + trace!("initializing deno system"); + let desc = self + .scx + .callbacks + .exec(self.desc.ctor_cb_key.clone(), serde_json::Value::Null) + .await?; + + let desc = serde_json::from_value(desc).wrap_err("protocol error")?; + + trace!("deno system initialized"); + + Ok(DenoSystemInstance { + desc, + scx: self.scx.clone(), + }) + } +} + +#[derive(Debug, Deserialize)] +/// This is the description sent from the typescript side for a registered manifest. +struct InstanceDesc { + load_lock_entry_cb_key: CHeapStr, + gen_lock_entry_cb_key: CHeapStr, + load_config_cb_key: CHeapStr, + cli_commands_cb_key: CHeapStr, +} + +pub struct DenoSystemInstance { + desc: InstanceDesc, + scx: DenoSystemsContext, +} + +#[async_trait::async_trait] +impl SystemInstance for DenoSystemInstance { + type LockState = serde_json::Value; + + async fn load_config( + &self, + config: serde_json::Value, + bb: Arc>, + state: Option, + ) -> Res<()> { + self.scx + .callbacks + .exec( + self.desc.load_config_cb_key.clone(), + json!({ + "config": config, + "bb": bb, + "state": state + }), + ) + .await + .wrap_err("callback error")?; + Ok(()) + } + + async fn load_lock_entry(&self, raw: serde_json::Value) -> Res { + self.scx + .callbacks + .exec( + self.desc.load_lock_entry_cb_key.clone(), + json!({ + "raw": raw + }), + ) + .await + .wrap_err("callback error") + } + + async fn gen_lock_entry(&self) -> Res { + self.scx + .callbacks + .exec(self.desc.gen_lock_entry_cb_key.clone(), json!({})) + .await + .wrap_err("callback error") + } + + async fn commands(&self) -> Res> { + let cmds = self + .scx + .callbacks + .exec(self.desc.cli_commands_cb_key.clone(), json!({})) + .await + .wrap_err("callback error")?; + + let cmds: Vec = + serde_json::from_value(cmds).wrap_err("protocol error")?; + + let cmds = cmds + .into_iter() + .map(|cmd| cmd.convert(self.scx.clone())) + .collect(); + + Ok(cmds) + } +} diff --git a/src/ghjk/systems/deno/cli.rs b/src/ghjk/systems/deno/cli.rs new file mode 100644 index 00000000..668d47d1 --- /dev/null +++ b/src/ghjk/systems/deno/cli.rs @@ -0,0 +1,400 @@ +//! Types and conversions for runtime specified CLI commands +//! from deno systems + +use crate::{interlude::*, systems::CliCommandAction}; + +#[derive(Debug, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct CliCommandDesc { + pub name: String, + + pub hide: Option, + + pub aliases: Option>, + pub visible_aliases: Option>, + + pub about: Option, + pub before_help: Option, + pub before_long_help: Option, + + pub args: Option>, + pub flags: Option>, + pub sub_commands: Option>, + + pub disable_help_subcommand: Option, + + pub action_cb_key: Option, +} + +impl CliCommandDesc { + #[tracing::instrument(skip(scx))] + pub fn convert(self, scx: super::DenoSystemsContext) -> crate::systems::SystemCliCommand { + let name = self.name; + let mut cmd = clap::Command::new(name.clone()).name(name.clone()); + + if let Some(val) = self.hide { + cmd = cmd.hide(val) + } + if let Some(val) = self.aliases { + cmd = cmd.aliases(val) + } + if let Some(val) = self.visible_aliases { + cmd = cmd.visible_aliases(val) + } + if let Some(val) = &self.about { + cmd = cmd.about(val) + } + if let Some(val) = self.before_help { + cmd = cmd.before_help(val) + } + if let Some(val) = self.before_long_help { + cmd = cmd.before_long_help(val) + } + if let Some(val) = self.disable_help_subcommand { + cmd = cmd.disable_help_subcommand(val) + } + let flag_ids = if let Some(val) = &self.flags { + let mut ids = ahash::HashSet::default(); + for (id, desc) in val { + ids.insert(id.clone()); + let arg = desc.convert(id); + cmd = cmd.arg(arg); + } + ids + } else { + default() + }; + + if let Some(val) = &self.args { + for (id, desc) in val { + if flag_ids.contains(id) { + panic!("flag and arg id clash at {id}"); + } + let arg = desc.convert(id); + cmd = cmd.arg(arg); + } + } + let sub_commands = if let Some(val) = self.sub_commands { + let mut subcommands = IndexMap::new(); + for desc in val { + let id = desc.name.clone(); + let scmd = desc.convert(scx.clone()); + subcommands.insert(id.into(), scmd); + } + subcommands + } else { + default() + }; + + let action: Option = if let Some(val) = self.action_cb_key { + let cb_key = CHeapStr::from(val); + let flags = self.flags.unwrap_or_default(); + let flags = Arc::new(flags); + let args = self.args.unwrap_or_default(); + let args = Arc::new(args); + Some(Box::new(move |matches| { + let scx = scx.clone(); + let cb_key = cb_key.clone(); + let flags = flags.clone(); + let args = args.clone(); + deno_cb_action(matches, scx.clone(), cb_key, flags, args).boxed() + })) + } else { + /* if sub_commands.is_empty() { + error!("a system command has no action or subcommands attached"); + } */ + None + }; + + crate::systems::SystemCliCommand { + name: name.into(), + clap: cmd, + sub_commands, + action, + } + } +} + +async fn deno_cb_action( + mut matches: clap::ArgMatches, + scx: super::DenoSystemsContext, + cb_key: CHeapStr, + flag_descs: Arc>, + args_descs: Arc>, +) -> Res<()> { + let mut flags = IndexMap::new(); + let mut args = IndexMap::new(); + + let match_ids = matches + .ids() + .map(|id| id.as_str().to_owned()) + .collect::>() + .into_iter(); + for id in match_ids { + let Some(desc) = flag_descs + .get(&id) + .map(|flag| &flag.arg) + .or_else(|| args_descs.get(&id)) + else { + unreachable!("unspecified arg id found: {id}"); + }; + let value = match desc.action.unwrap_or(ArgActionSerde::Set) { + ArgActionSerde::Set => matches + .try_remove_one::(id.as_str()) + .wrap_err_with(|| format!("error extracting match string for {id}"))? + .map(|val| json!(val)), + ArgActionSerde::Append => matches + .try_remove_many::(id.as_str()) + .wrap_err_with(|| format!("error extracting match bool for {id}"))? + .map(|vals| vals.collect::>()) + .map(|val| json!(val)), + ArgActionSerde::SetTrue | ArgActionSerde::SetFalse => matches + .try_remove_one::(id.as_str()) + .wrap_err_with(|| format!("error extracting match bool for {id}"))? + .map(|val| json!(val)), + ArgActionSerde::Count => matches + .try_remove_one::(id.as_str()) + .wrap_err_with(|| format!("error extracting match count for {id}"))? + .map(|val| json!(val)), + ArgActionSerde::Help + | ArgActionSerde::HelpShort + | ArgActionSerde::HelpLong + | ArgActionSerde::Version => unreachable!(), + }; + let Some(value) = value else { + continue; + }; + + let bucket = if flag_descs.contains_key(id.as_str()) { + &mut flags + } else { + &mut args + }; + + bucket.insert(id.as_str().to_owned(), value); + } + let response = scx + .callbacks + .exec( + cb_key.clone(), + json!({ + "flags": flags, + "args": args + }), + ) + .await + .wrap_err("callback error")?; + debug!(?response, "system command action response"); + Ok(()) +} + +#[derive(Debug, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct CliArgDesc { + pub required: Option, + pub global: Option, + pub hide: Option, + pub exclusive: Option, + pub trailing_var_arg: Option, + pub allow_hyphen_values: Option, + + pub action: Option, + + pub value_name: Option, + pub value_hint: Option, + + pub long: Option, + pub long_aliases: Option>, + pub visible_long_aliases: Option>, + + pub short: Option, + pub short_aliases: Option>, + pub visible_short_aliases: Option>, + + pub env: Option, + + pub help: Option, + pub long_help: Option, +} + +impl CliArgDesc { + pub fn convert(&self, id: &str) -> clap::Arg { + let mut arg = clap::Arg::new(id.to_owned()); + + if let Some(val) = self.required { + arg = arg.required(val) + } + if let Some(val) = self.global { + arg = arg.global(val) + } + if let Some(val) = self.hide { + arg = arg.hide(val) + } + if let Some(val) = self.exclusive { + arg = arg.exclusive(val) + } + if let Some(val) = self.trailing_var_arg { + arg = arg.num_args(..).trailing_var_arg(val) + } + if let Some(val) = self.allow_hyphen_values { + arg = arg.allow_hyphen_values(val) + } + + if let Some(val) = self.action { + arg = arg.action(clap::ArgAction::from(val)) + } + + if let Some(val) = &self.value_name { + arg = arg.value_name(val) + } + + if let Some(val) = self.value_hint { + arg = arg.value_hint(clap::ValueHint::from(val)) + } + + if let Some(val) = &self.long { + arg = arg.long(val) + } + if let Some(val) = &self.long_aliases { + arg = arg.aliases(val) + }; + if let Some(val) = &self.visible_long_aliases { + arg = arg.visible_aliases(val) + }; + + if let Some(val) = self.short { + arg = arg.short(val) + }; + if let Some(val) = &self.short_aliases { + arg = arg.short_aliases(val.clone()) + }; + if let Some(val) = &self.visible_short_aliases { + arg = arg.short_aliases(val.clone()) + }; + + if let Some(val) = &self.env { + arg = arg.env(val) + }; + + if let Some(val) = &self.help { + arg = arg.help(val) + }; + + if let Some(val) = &self.long_help { + arg = arg.long_help(val) + }; + + arg + } +} + +#[derive(Debug, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct CliFlagDesc { + #[serde(flatten)] + pub arg: CliArgDesc, + + pub long: Option, + pub long_aliases: Option>, + pub visible_long_aliases: Option>, + + pub short: Option, + pub short_aliases: Option>, + pub visible_short_aliases: Option>, +} + +impl CliFlagDesc { + pub fn convert(&self, id: &str) -> clap::Arg { + let mut arg = self.arg.convert(id); + + if let Some(val) = &self.long { + arg = arg.long(val) + } + if let Some(val) = &self.long_aliases { + arg = arg.aliases(val) + }; + if let Some(val) = &self.visible_long_aliases { + arg = arg.visible_aliases(val) + }; + + if let Some(val) = self.short { + arg = arg.short(val) + }; + if let Some(val) = &self.short_aliases { + arg = arg.short_aliases(val.clone()) + }; + if let Some(val) = &self.visible_short_aliases { + arg = arg.short_aliases(val.clone()) + }; + + arg + } +} + +#[derive(Deserialize, Debug, Clone, Copy)] +pub enum ValueHintSerde { + Unknown, + Other, + AnyPath, + FilePath, + DirPath, + ExecutablePath, + CommandName, + CommandString, + CommandWithArguments, + Username, + Hostname, + Url, + EmailAddress, +} + +impl From for clap::ValueHint { + fn from(val: ValueHintSerde) -> Self { + use ValueHintSerde::*; + match val { + Unknown => clap::ValueHint::Unknown, + Other => clap::ValueHint::Other, + AnyPath => clap::ValueHint::AnyPath, + FilePath => clap::ValueHint::FilePath, + DirPath => clap::ValueHint::DirPath, + ExecutablePath => clap::ValueHint::ExecutablePath, + CommandName => clap::ValueHint::CommandName, + CommandString => clap::ValueHint::CommandString, + CommandWithArguments => clap::ValueHint::CommandWithArguments, + Username => clap::ValueHint::Username, + Hostname => clap::ValueHint::Hostname, + Url => clap::ValueHint::Url, + EmailAddress => clap::ValueHint::EmailAddress, + } + } +} + +#[derive(Deserialize, Debug, Clone, Copy)] +pub enum ArgActionSerde { + Set, + Append, + SetTrue, + SetFalse, + Count, + Help, + HelpShort, + HelpLong, + Version, +} + +impl From for clap::ArgAction { + fn from(val: ArgActionSerde) -> Self { + use ArgActionSerde::*; + match val { + Set => clap::ArgAction::Set, + Append => clap::ArgAction::Append, + SetTrue => clap::ArgAction::SetTrue, + SetFalse => clap::ArgAction::SetFalse, + Count => clap::ArgAction::Count, + Help => clap::ArgAction::Help, + HelpShort => clap::ArgAction::HelpShort, + HelpLong => clap::ArgAction::HelpLong, + Version => clap::ArgAction::Version, + } + } +} diff --git a/src/ghjk/utils.rs b/src/ghjk/utils.rs new file mode 100644 index 00000000..f3d7422c --- /dev/null +++ b/src/ghjk/utils.rs @@ -0,0 +1,261 @@ +use crate::interlude::*; + +use std::io::Write; + +#[inline] +pub fn default() -> T { + T::default() +} + +pub type DHashMap = dashmap::DashMap; +pub use cheapstr::CHeapStr; + +mod cheapstr { + use crate::interlude::*; + + use std::{ + borrow::Cow, + hash::{Hash, Hasher}, + }; + // lifted from github.com/bevyengine/bevy 's bevy_core/Name struct + // MIT/APACHE2 licence + #[derive(Clone, Serialize, Deserialize)] + #[serde(crate = "serde", from = "String", into = "String")] + pub struct CHeapStr { + hash: u64, + string: Cow<'static, str>, + } + + impl CHeapStr { + /// Creates a new [`IdUnique`] from any string-like type. + pub fn new(string: impl Into>) -> Self { + let string = string.into(); + let mut id = Self { string, hash: 0 }; + id.update_hash(); + id + } + + /// Gets the name of the entity as a `&str`. + #[inline] + pub fn as_str(&self) -> &str { + &self.string + } + + fn update_hash(&mut self) { + let mut hasher = ahash::AHasher::default(); + self.string.hash(&mut hasher); + self.hash = hasher.finish(); + } + } + + impl From for CHeapStr + where + T: Into>, + { + #[inline(always)] + fn from(string: T) -> Self { + Self::new(string) + } + } + + impl Hash for CHeapStr { + fn hash(&self, state: &mut H) { + self.string.hash(state); + } + } + + impl PartialEq for CHeapStr { + fn eq(&self, other: &Self) -> bool { + if self.hash != other.hash { + // Makes the common case of two strings not been equal very fast + return false; + } + + self.string.eq(&other.string) + } + } + + impl Eq for CHeapStr {} + + impl PartialOrd for CHeapStr { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } + } + + impl Ord for CHeapStr { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.string.cmp(&other.string) + } + } + + impl std::ops::Deref for CHeapStr { + type Target = Cow<'static, str>; + + fn deref(&self) -> &Self::Target { + &self.string + } + } + + impl std::borrow::Borrow for CHeapStr { + fn borrow(&self) -> &str { + &self[..] + } + } + + impl From for String { + fn from(value: CHeapStr) -> String { + // FIXME: optmize this + /* let string = if let Some(s) = Arc::get_mut(&mut self.0) { + unsafe { + String::from_raw_parts( + s as *mut str as *mut u8, + s.len(), + s.len() + ) + } + } else { + (&self.0[..]).to_string() + }; + std::mem::forget(self.0); + string */ + value.string.into_owned() + } + } + + impl std::fmt::Display for CHeapStr { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.string.fmt(f) + } + } + + impl std::fmt::Debug for CHeapStr { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.string.fmt(f) + } + } +} + +const SHA2_256: u64 = 0x12; + +pub fn hash_obj(obj: &T) -> String { + use sha2::Digest; + let mut hash = sha2::Sha256::new(); + json_canon::to_writer(&mut hash, obj).expect_or_log("error serializing manifest"); + let hash = hash.finalize(); + + let hash = + multihash::Multihash::<32>::wrap(SHA2_256, &hash[..]).expect_or_log("error multihashing"); + encode_base32_multibase(hash.digest()) +} + +pub fn hash_str(string: &str) -> String { + hash_bytes(string.as_bytes()) +} + +pub fn hash_bytes(bytes: &[u8]) -> String { + use sha2::Digest; + let mut hash = sha2::Sha256::new(); + hash.write(bytes).expect_or_log("error writing to hasher"); + let hash = hash.finalize(); + + let hash = + multihash::Multihash::<32>::wrap(SHA2_256, &hash[..]).expect_or_log("error multihashing"); + encode_base32_multibase(hash.digest()) +} + +pub async fn hash_reader(reader: T) -> Res { + use sha2::Digest; + use tokio::io::*; + let mut hash = sha2::Sha256::new(); + let mut buf = vec![0u8; 65536]; + + let reader = tokio::io::BufReader::new(reader); + + let mut reader = std::pin::pin!(reader); + + loop { + // Read a chunk of data + let bytes_read = reader.read(&mut buf).await?; + + // Break the loop if we reached EOF + if bytes_read == 0 { + break; + } + hash.write(&buf[..bytes_read]) + .expect_or_log("error writing to hasher"); + } + let hash = hash.finalize(); + + let hash = + multihash::Multihash::<32>::wrap(SHA2_256, &hash[..]).expect_or_log("error multihashing"); + let hash = encode_base32_multibase(hash.digest()); + Ok(hash) +} + +pub fn encode_base32_multibase>(source: T) -> String { + format!( + "b{}", + data_encoding::BASE32_NOPAD + .encode(source.as_ref()) + .to_lowercase() + ) +} + +#[allow(unused)] +// Consider z-base32 https://en.wikipedia.org/wiki/Base32#z-base-32 +pub fn decode_base32_multibase(source: &str) -> eyre::Result> { + match ( + &source[0..1], + data_encoding::BASE32_NOPAD.decode(source[1..].as_bytes()), + ) { + ("b", Ok(bytes)) => Ok(bytes), + (prefix, Ok(_)) => Err(eyre::format_err!( + "unexpected multibase prefix for base32 multibase: {prefix}" + )), + (_, Err(err)) => Err(eyre::format_err!("error decoding base32: {err}")), + } +} + +#[allow(unused)] +pub fn encode_hex_multibase>(source: T) -> String { + format!( + "f{}", + data_encoding::HEXLOWER_PERMISSIVE.encode(source.as_ref()) + ) +} + +#[allow(unused)] +pub fn decode_hex_multibase(source: &str) -> eyre::Result> { + match ( + &source[0..1], + data_encoding::HEXLOWER_PERMISSIVE.decode(source[1..].as_bytes()), + ) { + ("f", Ok(bytes)) => Ok(bytes), + (prefix, Ok(_)) => Err(eyre::format_err!( + "unexpected multibase prefix for hex multibase: {prefix}" + )), + (_, Err(err)) => Err(eyre::format_err!("error decoding hex: {err}")), + } +} + +pub async fn find_entry_recursive(from: &Path, name: &str) -> Res> { + let mut cur = from; + loop { + let location = cur.join(name); + match tokio::fs::try_exists(&location).await { + Ok(true) => { + return Ok(Some(location)); + } + Err(err) if err.kind() != std::io::ErrorKind::NotFound => { + return Err(err).wrap_err("error on file stat"); + } + _ => { + let Some(next_cur) = cur.parent() else { + return Ok(None); + }; + cur = next_cur; + } + } + } +} diff --git a/src/play/Cargo.toml b/src/play/Cargo.toml new file mode 100644 index 00000000..f12e33aa --- /dev/null +++ b/src/play/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "play" +version.workspace = true +edition.workspace = true + +[[bin]] +name = "play" +path = "main.rs" + +[dependencies] + +tracing-unwrap.workspace = true + +color-eyre.workspace = true +tracing.workspace = true +tracing-subscriber.workspace = true +once_cell.workspace = true +clap = { workspace = true, features = ["derive", "env"] } +tokio = { workspace = true, features = ["full", "parking_lot"] } +data-encoding = "2.6.0" +sha2 = "0.10.8" +futures-concurrency = "7.6.2" diff --git a/src/play/main.rs b/src/play/main.rs new file mode 100644 index 00000000..6994e430 --- /dev/null +++ b/src/play/main.rs @@ -0,0 +1,20 @@ +#![allow(unused)] + +use futures_concurrency::prelude::*; +use std::{ + collections::HashMap, + path::{Path, PathBuf}, +}; + +type BoxErr = Box; +type Res = Result; + +fn main() { + tokio::runtime::Builder::new_current_thread() + .enable_all() + .build() + .unwrap() + .block_on(async { + // playground + }); +} diff --git a/src/xtask/Cargo.toml b/src/xtask/Cargo.toml new file mode 100644 index 00000000..8bda8e04 --- /dev/null +++ b/src/xtask/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "xtask" +version.workspace = true +edition.workspace = true + +[[bin]] +name = "xtask" +path = "main.rs" + +[dependencies] +denort.workspace = true + +tracing-unwrap.workspace = true + +color-eyre.workspace = true +tracing.workspace = true +tracing-subscriber.workspace = true +once_cell.workspace = true +clap = { workspace = true, features = ["derive", "env"] } diff --git a/src/xtask/main.rs b/src/xtask/main.rs new file mode 100644 index 00000000..a1841abd --- /dev/null +++ b/src/xtask/main.rs @@ -0,0 +1,99 @@ +#[allow(unused)] +mod interlude { + pub use std::future::Future; + pub use std::path::{Path, PathBuf}; + pub use std::sync::Arc; + + pub use color_eyre::eyre; + pub use eyre::{format_err as ferr, Context, Result as Res, WrapErr}; + pub use tracing::{debug, error, info, trace, warn}; + pub use tracing_unwrap::*; +} +use clap::builder::styling::AnsiColor; + +use crate::interlude::*; + +mod utils; + +fn main() -> Res<()> { + utils::setup_tracing()?; + let cwd = std::env::current_dir()?; + + use clap::Parser; + let args = Args::parse(); + match args.command { + Commands::Test { files, filter } => { + use denort::deno::deno_config; + denort::test_sync( + deno_config::glob::FilePatterns { + include: if let Some(vec) = files { + Some(deno_config::glob::PathOrPatternSet::new( + vec.into_iter() + .map(|path| { + deno_config::glob::PathOrPattern::from_relative(&cwd, &path) + }) + .collect::, _>>()?, + )) + } else { + None + }, + exclude: deno_config::glob::PathOrPatternSet::new(vec![]), + base: cwd, + }, + "deno.jsonc".into(), + denort::deno::args::PermissionFlags { + allow_all: true, + ..Default::default() + }, + None, + filter, + Arc::new(std::vec::Vec::new), + vec![], + ) + } /* Commands::Run { argv } => denort::run_sync( + denort::deno::deno_runtime::deno_core::resolve_url_or_path("ghjk.ts", &cwd).unwrap(), + Some("deno.jsonc".into()), + denort::deno::args::PermissionFlags { + allow_all: true, + ..Default::default() + }, + Arc::new(std::vec::Vec::new), + ), */ + } + + Ok(()) +} + +const CLAP_STYLE: clap::builder::Styles = clap::builder::Styles::styled() + .header(AnsiColor::Yellow.on_default()) + .usage(AnsiColor::Green.on_default()) + .literal(AnsiColor::Green.on_default()) + .placeholder(AnsiColor::Green.on_default()); + +#[derive(Debug, clap::Parser)] +#[clap( + version, + about, + styles = CLAP_STYLE +)] +struct Args { + #[clap(subcommand)] + command: Commands, +} + +#[derive(Debug, clap::Subcommand)] +enum Commands { + /* #[clap(visible_alias = "r")] + Run { + /// Script arg + argv: Vec, + }, */ + #[clap(visible_alias = "t")] + Test { + /// Files to test + files: Option>, + /// Tests to include + #[arg(long)] + filter: Option, + }, +} diff --git a/src/xtask/utils.rs b/src/xtask/utils.rs new file mode 100644 index 00000000..32026b1c --- /dev/null +++ b/src/xtask/utils.rs @@ -0,0 +1,29 @@ +use crate::interlude::*; + +// Ensure that the `tracing` stack is only initialised once using `once_cell` +// isn't required in cargo-nextest since each test runs in a new process +#[cfg(test)] +pub fn _setup_tracing_once() { + use once_cell::sync::Lazy; + static TRACING: Lazy<()> = Lazy::new(|| { + setup_tracing().expect("failed to init tracing"); + }); + Lazy::force(&TRACING); +} + +pub fn setup_tracing() -> eyre::Result<()> { + color_eyre::install()?; + if std::env::var("RUST_LOG").is_err() { + std::env::set_var("RUST_LOG", "info"); + } + + // tracing_log::LogTracer::init()?; + tracing_subscriber::fmt() + .compact() + .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) + .with_timer(tracing_subscriber::fmt::time::uptime()) + .try_init() + .map_err(|err| eyre::eyre!(err))?; + + Ok(()) +} diff --git a/std/sedLock.ts b/std/sedLock.ts index 9219b807..a32af009 100644 --- a/std/sedLock.ts +++ b/std/sedLock.ts @@ -1,3 +1,7 @@ +/** + * TODO: show diff on replacement. + */ + import { $, Path, unwrapZodRes } from "../utils/mod.ts"; import { std_fs, zod } from "../deps/common.ts"; @@ -40,6 +44,8 @@ export async function sedLock( let dirty = false; + const workSet = [] as [Path, string][]; + await $.co( Object .entries(lines) @@ -88,8 +94,7 @@ export async function sedLock( const newText = rewrite.join("\n"); if (text != newText) { - await path.writeText(newText); - $.logStep(`Updated ${workingDir.relative(path)}`); + workSet.push([path, newText]); dirty = true; } else { // $.logLight(`No change ${workingDir.relative(path)}`); @@ -107,5 +112,17 @@ export async function sedLock( }), ); + // we prefer all settled for the destructive operation + (await Promise.allSettled( + workSet.map(async ([path, newText]) => { + await path.writeText(newText); + $.logStep(`Updated ${workingDir.relative(path)}`); + }), + )).forEach((res) => { + if (res.status == "rejected") { + throw res.reason; + } + }); + return dirty; } diff --git a/tests/envHooks.ts b/tests/envHooks.ts index 963ea072..f62ac73f 100644 --- a/tests/envHooks.ts +++ b/tests/envHooks.ts @@ -49,7 +49,7 @@ const fishInteractiveScript = [ ] .join("\n"); -type CustomE2eTestCase = Omit & { +type CustomE2eTestCase = Omit & { ePoint: string; stdin: string; }; @@ -60,9 +60,7 @@ const cases: CustomE2eTestCase[] = [ // -s: read from stdin // -l: login mode // -i: make it interactive - ePoint: Deno.env.get("GHJK_TEST_E2E_TYPE") == "local" - ? `bash --rcfile $BASH_ENV -si` // we don't want to use the system rcfile - : `bash -sil`, + ePoint: `bash --rcfile $BASH_ENV -si`, // we don't want to use the system rcfile stdin: posixInteractiveScript, }, { @@ -80,7 +78,8 @@ const cases: CustomE2eTestCase[] = [ harness(cases.map((testCase) => ({ ...testCase, - tsGhjkfileStr: ` + fs: { + "ghjk.ts": ` export { sophon } from "$ghjk/hack.ts"; import { task, env } from "$ghjk/hack.ts"; @@ -88,6 +87,7 @@ env("main") .onEnter(task($ => $\`/bin/sh -c 'echo remark > marker'\`)) .onExit(task($ => $\`/bin/sh -c 'rm marker'\`)) `, + }, ePoints: [{ cmd: testCase.ePoint, stdin: testCase.stdin }], name: `envHooks/${testCase.name}`, }))); diff --git a/tests/envs.ts b/tests/envs.ts index 7318226a..b7f19007 100644 --- a/tests/envs.ts +++ b/tests/envs.ts @@ -9,7 +9,7 @@ import dummy from "../ports/dummy.ts"; import type { FileArgs } from "../mod.ts"; type CustomE2eTestCase = - & Omit + & Omit & { ePoint: string; stdin: string; @@ -47,11 +47,18 @@ const envVarTestEnvs: EnvDefArgs[] = [ ]; const envVarTestsPosix = ` set -ex +env # by default, we should be in main -[ "$SONG" = "ditto" ] || exit 101 +[ "$SONG" = "ditto" ] || exit 1010 [ "$GHJK_ENV" = "main" ] || exit 1011 +# vars should be gone after deactivation +ghjk_deactivate +[ "$SONG" = "ditto" ] && exit 1022 +[ "$GHJK_ENV" = "main" ] && exit 1022 + ghjk envs cook sss +echo $? . .ghjk/envs/sss/activate.sh # by default, envs should be based on main # so they should inherit it's env vars @@ -60,6 +67,7 @@ ghjk envs cook sss [ "$GHJK_ENV" = "sss" ] || exit 1012 # go back to main and "sss" variables shouldn't be around +# through deactivation . .ghjk/envs/main/activate.sh [ "$SONG" = "ditto" ] || exit 104 [ "$SING" = "Seoul Sonyo Sound" ] && exit 105 @@ -78,6 +86,11 @@ set fish_trace 1 test "$SONG" = "ditto"; or exit 101; test "$GHJK_ENV" = "main"; or exit 1010; +# vars should be gone after deactivation +ghjk_deactivate +test "$SONG" = "ditto"; and exit 101; +test "$GHJK_ENV" = "main"; and exit 1010; + ghjk envs cook sss . .ghjk/envs/sss/activate.fish # by default, envs should be based on main @@ -131,6 +144,7 @@ ghjk envs cook foo const installTestsFish = ` set fish_trace 1 + # by default, we should be in main test (dummy) = "main"; or exit 101; @@ -186,6 +200,7 @@ const cases: CustomE2eTestCase[] = [ secureConfig: { defaultEnv: "yuki" }, stdin: ` set fish_trace 1 + # env base is false for "yuki" and thus no vars from "main" test "$GHJK_ENV" = "yuki"; or exit 106 test "$SONG" = "ditto"; and exit 107 @@ -320,14 +335,16 @@ test (dummy) = "e1"; or exit 105 harness(cases.map((testCase) => ({ ...testCase, - tsGhjkfileStr: "ghjkTs" in testCase ? testCase.ghjkTs : genTsGhjkFile( - { - secureConf: { - ...testCase.secureConfig, - envs: [...testCase.envs, ...(testCase.secureConfig?.envs ?? [])], + fs: { + "ghjk.ts": "ghjkTs" in testCase ? testCase.ghjkTs : genTsGhjkFile( + { + secureConf: { + ...testCase.secureConfig, + envs: [...testCase.envs, ...(testCase.secureConfig?.envs ?? [])], + }, }, - }, - ), + ), + }, ePoints: [{ cmd: testCase.ePoint, stdin: testCase.stdin }], name: `envs/${testCase.name}`, }))); diff --git a/tests/hashfile.ts b/tests/hashfile.ts new file mode 100644 index 00000000..a7227379 --- /dev/null +++ b/tests/hashfile.ts @@ -0,0 +1,75 @@ +import "../setup_logger.ts"; +import { E2eTestCase, harness } from "./utils.ts"; + +type CustomE2eTestCase = Omit & { + stdin: string; +}; + +const cases: CustomE2eTestCase[] = [ + { + name: "invalidated_control", + stdin: ` +__ghjk_get_mtime_ts .ghjk/hash.json > tstamp +ghjk sync +test (cat tstamp) = (__ghjk_get_mtime_ts .ghjk/hash.json); or exit 101 +ghjk sync +test (cat tstamp) = (__ghjk_get_mtime_ts .ghjk/hash.json); or exit 101 +`, + }, + { + name: "invalidated_ghjk_modified", + stdin: ` +__ghjk_get_mtime_ts .ghjk/hash.json > tstamp +echo '// hey' >> ghjk.ts +ghjk sync +test (cat tstamp) -lt (__ghjk_get_mtime_ts .ghjk/hash.json); or exit 101 +`, + }, + { + name: "invalidated_dep_script_modified", + stdin: ` +__ghjk_get_mtime_ts .ghjk/hash.json > tstamp +echo '// hey' >> extra.ts +ghjk sync +test (cat tstamp) -lt (__ghjk_get_mtime_ts .ghjk/hash.json); or exit 101 +`, + }, + { + name: "invalidated_env_modified", + stdin: ` +__ghjk_get_mtime_ts .ghjk/hash.json > tstamp +MY_ENV=changed ghjk sync +test (cat tstamp) -lt (__ghjk_get_mtime_ts .ghjk/hash.json); or exit 101 +`, + }, + { + name: "invalidated_listed_file_removed", + stdin: ` +__ghjk_get_mtime_ts .ghjk/hash.json > tstamp +rm dir/one +ghjk sync +test (cat tstamp) -lt (__ghjk_get_mtime_ts .ghjk/hash.json); or exit 101 +`, + }, +]; + +harness(cases.map((testCase) => ({ + ...testCase, + fs: { + "ghjk.ts": ` +export { sophon } from "$ghjk/hack.ts"; +import { task, env } from "$ghjk/hack.ts"; +import {stuff} from "./extra.ts" + +await Array.fromAsync(Deno.readDir("dir")) + +env("main") + .vars({ hello: Deno.env.get("MY_ENV") ?? "world" }) +`, + "extra.ts": `export const stuff = "hello"`, + "dir/one": "1", + "dir/two": "2", + }, + ePoints: [{ cmd: "fish", stdin: testCase.stdin }], + name: `hashfile/${testCase.name}`, +}))); diff --git a/tests/ports.ts b/tests/ports.ts index 9559bdf4..8487bba2 100644 --- a/tests/ports.ts +++ b/tests/ports.ts @@ -6,11 +6,14 @@ import dummy from "../ports/dummy.ts"; import type { InstallConfigFat } from "../modules/ports/types.ts"; import { testTargetPlatform } from "./utils.ts"; -type CustomE2eTestCase = Omit & { +type CustomE2eTestCase = Omit & { ePoint: string; installConf: InstallConfigFat | InstallConfigFat[]; secureConf?: FileArgs; }; + +// FIXME: where did the asdf test go? + // order tests by download size to make failed runs less expensive const cases: CustomE2eTestCase[] = [ // 0 megs @@ -25,6 +28,17 @@ const cases: CustomE2eTestCase[] = [ installConf: ports.jq_ghrel(), ePoint: `jq --version`, }, + { + name: "asdf-jq", + ePoint: `jq --version`, + installConf: ports.asdf({ + pluginRepo: "https://github.com/lsanwick/asdf-jq", + installType: "version", + }), + secureConf: { + enableRuntimes: true, + }, + }, // 3 megs { name: "protoc", @@ -68,6 +82,19 @@ const cases: CustomE2eTestCase[] = [ installConf: ports.rustup(), ePoint: `rustup-init --version`, }, + // 15 megs + { + name: "fx_ghrel", + installConf: ports.fx_ghrel(), + ePoint: `fx --version`, + }, + // 22 megs + { + name: "livekit_cli_ghrel", + installConf: ports.livekit_cli_ghrel(), + ePoint: `lk --version`, + ignore: Deno.build.os == "darwin", + }, // 23 megs { name: "temporal", @@ -134,14 +161,7 @@ const cases: CustomE2eTestCase[] = [ ports.meta_cli_ghrel({ full: true }), ports.wasmedge(), ], - ePoint: Deno.env.get("GHJK_TEST_E2E_TYPE") != "local" - // meta cli runs into segmentation error in the alpine - // image - // https://github.com/metatypedev/metatype/issues/584 - // just check that the shell's able to find the - // executrable - ? `which meta && wasmedge --version` - : `meta --version && wasmedge --version`, + ePoint: `which meta && wasmedge --version`, ignore: testTargetPlatform == "linux/aarch64", }, // 80 meg @@ -150,15 +170,6 @@ const cases: CustomE2eTestCase[] = [ installConf: ports.cpy_bs(), ePoint: `python3 --version`, }, - // 77 meg +, depends on "cpy_bs" on darwin/macos - { - name: "cmake", - installConf: ports.cmake({}), - ePoint: `cmake --version`, - secureConf: { - enableRuntimes: true, - }, - }, // 80 meg + { name: "pipi-poetry", @@ -187,6 +198,9 @@ const cases: CustomE2eTestCase[] = [ profile: "minimal", }, }), + secureConf: { + enableRuntimes: true, + }, ePoint: `sd --version`, }, // rust + cargo_binstall + 22 megs @@ -199,22 +213,27 @@ const cases: CustomE2eTestCase[] = [ profile: "minimal", }, }), + secureConf: { + enableRuntimes: true, + }, ePoint: `sd --version`, }, ]; harness(cases.map((testCase) => ({ ...testCase, - tsGhjkfileStr: genTsGhjkFile( - { - secureConf: { - ...testCase.secureConf, - installs: Array.isArray(testCase.installConf) - ? testCase.installConf - : [testCase.installConf], + fs: { + "ghjk.ts": genTsGhjkFile( + { + secureConf: { + ...testCase.secureConf, + installs: Array.isArray(testCase.installConf) + ? testCase.installConf + : [testCase.installConf], + }, }, - }, - ), + ), + }, ePoints: [ ...["bash -c", "fish -c", "zsh -c"].map((sh) => ({ cmd: [...`env ${sh}`.split(" "), `"${testCase.ePoint}"`], diff --git a/tests/portsOutdated.ts b/tests/portsOutdated.ts index e079279f..4e4b0139 100644 --- a/tests/portsOutdated.ts +++ b/tests/portsOutdated.ts @@ -4,7 +4,7 @@ import * as ports from "../ports/mod.ts"; import type { InstallConfigFat } from "../modules/ports/types.ts"; import { FileArgs } from "../mod.ts"; -type CustomE2eTestCase = Omit & { +type CustomE2eTestCase = Omit & { ePoint: string; installConf: InstallConfigFat | InstallConfigFat[]; secureConf?: FileArgs; @@ -26,7 +26,7 @@ const cases: CustomE2eTestCase[] = [ name: "update_all", installConf: [ ports.jq_ghrel({ version: "jq-1.7" }), - ports.protoc({ version: "v24.0" }), + ports.protoc({ version: "v28.2" }), ], ePoint: `ghjk p outdated --update-all`, secureConf: { @@ -37,16 +37,18 @@ const cases: CustomE2eTestCase[] = [ harness(cases.map((testCase) => ({ ...testCase, - tsGhjkfileStr: genTsGhjkFile( - { - secureConf: { - ...testCase.secureConf, - installs: Array.isArray(testCase.installConf) - ? testCase.installConf - : [testCase.installConf], + fs: { + "ghjk.ts": genTsGhjkFile( + { + secureConf: { + ...testCase.secureConf, + installs: Array.isArray(testCase.installConf) + ? testCase.installConf + : [testCase.installConf], + }, }, - }, - ), + ), + }, ePoints: [ ...["bash -c", "fish -c", "zsh -c"].map((sh) => ({ cmd: [...`env ${sh}`.split(" "), `"${testCase.ePoint}"`], diff --git a/tests/reloadHooks.ts b/tests/reloadHooks.ts index 8f03679a..a29fa5db 100644 --- a/tests/reloadHooks.ts +++ b/tests/reloadHooks.ts @@ -1,7 +1,7 @@ import "../setup_logger.ts"; import { E2eTestCase, genTsGhjkFile, harness } from "./utils.ts"; import dummy from "../ports/dummy.ts"; -import type { InstallConfigFat } from "../port.ts"; +import { type InstallConfigFat } from "../port.ts"; // TODO: test for hook reload when ghjk.ts is touched // TODO: test for hook reload when nextfile is touched @@ -19,7 +19,7 @@ pushd ../ # it shouldn't be avail here set +ex [ $(dummy) ] && exit 102 -[ "\${DUMMY_ENV:-}" = "dummy" ] && exit 103 +[ "\${DUMMY_ENV:-}" = "old_dummy" ] || exit 103 set -ex # cd back in @@ -38,8 +38,8 @@ echo "test" > $GHJK_NEXTFILE const posixNonInteractiveScript = ` set -eux -# test that ghjk_reload is avail because BASH_ENV exposed by the suite -ghjk_reload +# items should be avail on new shell +# either due to auto hook and BASH_ENV/ZDOTDIR [ "\${DUMMY_ENV:-}" = "dummy" ] || exit 101 dummy @@ -50,20 +50,20 @@ sh -c "dummy" pushd ../ # no reload so it's stil avail dummy -ghjk_reload +ghjk_hook # it shouldn't be avail now [ $(set +e; dummy) ] && exit 102 -[ "\${DUMMY_ENV:-}" = "dummy" ] && exit 103 +[ "\${DUMMY_ENV:-}" = "old_dummy" ] || exit 103 # cd back in popd # not avail yet [ $(set +e; dummy) ] && exit 104 -[ "\${DUMMY_ENV:-}" = "dummy" ] && exit 105 +[ "\${DUMMY_ENV:-}" = "old_dummy" ] || exit 105 -ghjk_reload +ghjk_hook # now it should be avail dummy [ "\${DUMMY_ENV:-}" = "dummy" ] || exit 106 @@ -71,17 +71,30 @@ dummy [ "\${GHJK_ENV}" = "main" ] || exit 107 ghjk e cook test -ghjk_reload test +ghjk_hook test [ "\${GHJK_ENV:-}" = "test" ] || exit 110 -ghjk_reload +ghjk_hook [ "\${GHJK_ENV:-}" = "test" ] || exit 111 -GHJK_ENV=test ghjk_reload +GHJK_ENV=test ghjk_hook [ "\${GHJK_ENV:-}" = "test" ] || exit 112 `; -const fishScript = ` +// assumes BASH_ENV/ZDOTDIR +const posixNonInteractiveScriptNoHook = `set -eux +# test that ghjk_hook doesn't run by default on non-interactive shells +[ $(set +e; dummy) ] && exit 1021 +# [ "\${DUMMY_ENV:-}" = "dummy" ] && exit 1011 + +# test that ghjk_hook is avail because BASH_ENV exposed by the suite +ghjk_hook +` + posixNonInteractiveScript; + +const fishNonInteractiveScript = ` set fish_trace 1 + +# items should be avail on new shell +# either due to auto hook or custom code down below which dummy; or exit 101 test $DUMMY_ENV = "dummy"; or exit 102 @@ -90,23 +103,25 @@ sh -c '[ "$DUMMY_ENV" = "dummy" ]'; or exit 105 sh -c "dummy" pushd ../ -# it shouldn't be avail here +# no reload so it's stil avail +which dummy; or exit 1012 +test $DUMMY_ENV = "dummy"; or exit 1022 + +ghjk_hook +# it shouldn't be avail now which dummy; and exit 103 -test $DUMMY_ENV = "dummy"; and exit 104 +test $DUMMY_ENV = "old_dummy"; or exit 104 # cd back in popd +# not avail yet +which dummy; and exit 103 +test $DUMMY_ENV = "old_dummy"; or exit 104 + +ghjk_hook # now it should be avail dummy; or exit 123 test $DUMMY_ENV = "dummy"; or exit 105 -`; - -const fishNoninteractiveScript = ` -set fish_trace 1 -# test that ghjk_reload is avail because config.fish exposed by the suite -ghjk_reload - -${fishScript} # must cook test first ghjk envs cook test @@ -114,109 +129,190 @@ ghjk envs cook test test $GHJK_ENV = "main"; or exit 107 # manually switch to test -ghjk_reload test +ghjk_hook test test "$GHJK_ENV" = "test"; or exit 108 # re-invoking reload won't go back to main -ghjk_reload +ghjk_hook test "$GHJK_ENV" = "test"; or exit 109 # go back to main -ghjk_reload main +ghjk_hook main test "$GHJK_ENV" = "main"; or exit 111 # changing GHJK_ENV manually gets respected -GHJK_ENV=test ghjk_reload +GHJK_ENV=test ghjk_hook test "$GHJK_ENV" = "test"; or exit 112`; -const fishInteractiveScript = [ - fishScript, - // simulate interactive mode by emitting postexec after each line - // after each line - ...` +const fishNonInteractiveScriptNoHook = ` +set fish_trace 1 + +# test that ghjk_hook doesn't run by default on non-interactive shells +which dummy; and exit 1030 +test $DUMMY_ENV = "dummy"; and exit 1011 + +# test that ghjk_hook is avail because config.fish exposed by the suite +# simulate auto hook so that we can re-use test +ghjk_hook +` + fishNonInteractiveScript; + +// simulate interactive mode by emitting postexec after each line +// after each line. postexec isn't emitted by default on interactive +// fish shells +const fishInteractiveScript = ` +set fish_trace 1 +which dummy; or exit 101 +env +test $DUMMY_ENV = "dummy"; or exit 102 + +# it should be avail in subshells +sh -c '[ "$DUMMY_ENV" = "dummy" ]'; or exit 105 +sh -c "dummy" + +pushd ../ +# it shouldn't be avail here +which dummy; and exit 103 +test $DUMMY_ENV = "old_dummy"; or exit 104 + +# cd back in +popd +# now it should be avail +dummy; or exit 123 +test $DUMMY_ENV = "dummy"; or exit 105 + ghjk e cook test test $GHJK_ENV = "main"; or exit 107 echo "test" > $GHJK_NEXTFILE test "$GHJK_ENV" = "test"; or exit 108 -ghjk_reload main +ghjk_hook main test "$GHJK_ENV" = "main"; or exit 111 -GHJK_ENV=test ghjk_reload +GHJK_ENV=test ghjk_hook test "$GHJK_ENV" = "test"; or exit 112 ` - .split("\n").flatMap((line) => [ - line, - `emit fish_preexec`, - ]), -] + .split("\n") + .flatMap((line) => [ + line, + `emit fish_preexec;`, + ]) .join("\n"); -type CustomE2eTestCase = Omit & { +type CustomE2eTestCase = Omit & { installConf?: InstallConfigFat[]; ePoint: string; stdin: string; }; + +// -s: read from stdin +// -l: login mode +// -i: interactive mode +// we don't want to use the system rcfile +const bashInteractiveEpoint = `bash --rcfile $BASH_ENV -si`; + const cases: CustomE2eTestCase[] = [ { name: "bash_interactive", - // -s: read from stdin - // -l: login mode - // -i: interactive mode - ePoint: Deno.env.get("GHJK_TEST_E2E_TYPE") == "local" - ? `bash --rcfile $BASH_ENV -si` // we don't want to use the system rcfile - : `bash -sil`, + ePoint: bashInteractiveEpoint, stdin: posixInteractiveScript, + envVars: { + DUMMY_ENV: "old_dummy", + }, }, { name: "bash_scripting", ePoint: `bash -s`, + stdin: posixNonInteractiveScriptNoHook, + envVars: { + GHJK_AUTO_HOOK: "0", + DUMMY_ENV: "old_dummy", + }, + }, + { + // assumes BASH_ENV or ZDOTDIR are set + // for ghjk with GHJK_AUTO_HOOK set to 1 + name: "bash_scripting_with_auto_hook", + ePoint: `bash -s`, stdin: posixNonInteractiveScript, + envVars: { + DUMMY_ENV: "old_dummy", + }, }, { name: "zsh_interactive", ePoint: `zsh -sli`, stdin: posixInteractiveScript .split("\n").filter((line) => !/^#/.test(line)).join("\n"), + envVars: { + DUMMY_ENV: "old_dummy", + }, }, { name: "zsh_scripting", ePoint: `zsh -s`, + stdin: posixNonInteractiveScriptNoHook, + envVars: { + GHJK_AUTO_HOOK: "0", + DUMMY_ENV: "old_dummy", + }, + }, + { + // assumes BASH_ENV or ZDOTDIR are set + // for ghjk with GHJK_AUTO_HOOK set to 1 + name: "zsh_scripting_with_auto_hook", + ePoint: `zsh -s`, stdin: posixNonInteractiveScript, + envVars: { + DUMMY_ENV: "old_dummy", + }, }, { name: "fish_interactive", ePoint: `fish -il`, stdin: fishInteractiveScript, + envVars: { + DUMMY_ENV: "old_dummy", + }, }, { name: "fish_scripting", ePoint: `fish`, - // the fish implementation triggers changes - // on any pwd changes so it's identical to - // interactive usage - stdin: fishNoninteractiveScript, + stdin: fishNonInteractiveScriptNoHook, + envVars: { + GHJK_AUTO_HOOK: "0", + DUMMY_ENV: "old_dummy", + }, + }, + { + name: "fish_scripting_with_auto_hook", + ePoint: `fish`, + stdin: fishNonInteractiveScript, + envVars: { + DUMMY_ENV: "old_dummy", + }, }, ]; harness(cases.map((testCase) => ({ ...testCase, - tsGhjkfileStr: genTsGhjkFile( - { - secureConf: { - envs: [ - { - name: "main", - installs: testCase.installConf ? testCase.installConf : [dummy()], - }, - { - name: "test", - }, - ], + fs: { + "ghjk.ts": genTsGhjkFile( + { + secureConf: { + envs: [ + { + name: "main", + installs: testCase.installConf ? testCase.installConf : [dummy()], + }, + { + name: "test", + }, + ], + }, }, - }, - ), + ), + }, ePoints: [{ cmd: testCase.ePoint, stdin: testCase.stdin }], name: `reloadHooks/${testCase.name}`, }))); diff --git a/tests/tasks.ts b/tests/tasks.ts index d7040949..00b19eaf 100644 --- a/tests/tasks.ts +++ b/tests/tasks.ts @@ -4,7 +4,7 @@ import * as ghjk from "../mod.ts"; import * as ports from "../ports/mod.ts"; type CustomE2eTestCase = - & Omit + & Omit & { ePoint: string; stdin: string; @@ -171,16 +171,18 @@ test (cat output.txt) = 'A#STATIC, B#DYNAMIC' harness(cases.map((testCase) => ({ ...testCase, - tsGhjkfileStr: "ghjkTs" in testCase ? testCase.ghjkTs : genTsGhjkFile( - { - secureConf: { - tasks: Object.fromEntries( - testCase.tasks.map((def) => [def.name!, def]), - ), - enableRuntimes: testCase.enableRuntimesOnMasterPDAL, + fs: { + "ghjk.ts": "ghjkTs" in testCase ? testCase.ghjkTs : genTsGhjkFile( + { + secureConf: { + tasks: Object.fromEntries( + testCase.tasks.map((def) => [def.name!, def]), + ), + enableRuntimes: testCase.enableRuntimesOnMasterPDAL, + }, }, - }, - ), + ), + }, ePoints: [{ cmd: testCase.ePoint, stdin: testCase.stdin }], name: `tasks/${testCase.name}`, }))); diff --git a/tests/test-alpine.Dockerfile b/tests/test-alpine.Dockerfile deleted file mode 100644 index e9655187..00000000 --- a/tests/test-alpine.Dockerfile +++ /dev/null @@ -1,80 +0,0 @@ -ARG DENO_V=1.42.1 - -FROM docker.io/denoland/deno:alpine-${DENO_V} - -ARG BASH_V=5.2.21-r0 -ARG FISH_V=3.6.3-r0 -ARG ZSH_V=5.9-r2 -ARG GIT_V=2.43.0-r0 -ARG CURL_V=8.5.0-r0 -ARG XZ_V=5.4.5-r0 -ARG GTAR_V=1.35-r2 -ARG UNZIP_V=6.0-r14 -ARG ZSTD_V=1.5.5-r8 -ARG GCOMPAT_V=1.1.0-r4 -ARG BUILD_BASE_V=0.5-r3 - -RUN set -eux; \ - apk update; \ - apk add \ - # ambient deps \ - zstd=$ZSTD_V \ - tar=$GTAR_V \ - # test deps \ - bash=$BASH_V \ - fish=$FISH_V \ - zsh=$ZSH_V \ - # asdf deps \ - git=$GIT_V \ - curl=$CURL_V \ - xz=$XZ_V \ - unzip=$UNZIP_V \ - build-base=$BUILD_BASE_V \ - # gcompat=$GCOMPAT_V \ - ca-certificates \ - ; - -WORKDIR /ghjk - -COPY deno.lock deno.jsonc ./ -COPY deps/* ./deps/ -RUN deno task cache - -COPY . ./ - -RUN ln -s ./main.ts /bin/ghjk - -WORKDIR /app - -ENV GHJK_LOG=info -ENV GHJK_INSTALL_EXE_DIR=/usr/bin -ENV GHJK_INSTALL_HOOK_SHELLS=fish,bash,zsh -# share the module cache of the image -ENV GHJK_INSTALL_DENO_DIR=$DENO_DIR -RUN deno run -A /ghjk/install.ts - -ARG GITHUB_TOKEN -ENV GITHUB_TOKEN=$GITHUB_TOKEN - -# avoid variable expansion in the contents of the -# here-document by quoting the tag -COPY <<"EOT" /app/ghjk.ts -#{{CMD_ADD_CONFIG}} -EOT - -RUN <; - ePoints: { cmd: string | string[]; stdin?: string }[]; - timeout_ms?: number; - ignore?: boolean; - only?: boolean; -}; export const testTargetPlatform = Deno.env.get("DOCKER_PLATFORM") ?? (Deno.build.os + "/" + Deno.build.arch); @@ -28,136 +16,92 @@ if ( throw new Error(`unsupported test platform: ${testTargetPlatform}`); } -const dockerPlatform = `--platform=${ - testTargetPlatform - .replace("x86_64", "amd64") - .replace("aarch64", "arm64") -}`; - -const dockerCmd = (Deno.env.get("DOCKER_CMD") ?? "docker").split(/\s/); - -const dFileTemplate = await importRaw(import.meta.resolve("./test.Dockerfile")); -const templateStrings = { - addConfig: `#{{CMD_ADD_CONFIG}}`, +export type E2eTestCase = { + name: string; + fs: Record; + envVars?: Record; + ePoints: { cmd: string | string[]; stdin?: string }[]; + timeout_ms?: number; + ignore?: boolean; + only?: boolean; }; -const noRmi = Deno.env.get("DOCKER_NO_RMI"); - -export async function dockerE2eTest(testCase: E2eTestCase) { - const { name, envVars: testEnvs, ePoints, tsGhjkfileStr } = testCase; - const tag = `ghjk_e2e_${name}`.toLowerCase(); - const env = { - ...testEnvs, - }; - if (Deno.env.get("GITHUB_TOKEN")) { - env.GITHUB_TOKEN = Deno.env.get("GITHUB_TOKEN")!; - } - const devGhjkPath = import.meta.resolve("../"); - - const configFile = tsGhjkfileStr - // replace all file urls that point to the ghjk - // repo in the host fs to point to the copy of the - // repo in the image - .replaceAll(devGhjkPath, "file://$ghjk/") - .replaceAll("$ghjk", "/ghjk"); - - const dFile = dbg(dFileTemplate - .replace( - templateStrings.addConfig, - configFile - // escape all dollars - .replaceAll("$", "$$$$"), - )); - - await $ - .raw`${dockerCmd} buildx build ${dockerPlatform} ${ - Object.entries(env).map(([key, val]) => ["--build-arg", `${key}=${val}`]) - } --tag '${tag}' --network=host --output type=docker -f- .` - .env(env) - .stdinText(dFile); - - for (const ePoint of ePoints) { - let cmd = $.raw`${dockerCmd} run ${dockerPlatform} --rm ${[ - /* we want to enable interactivity when piping in */ - ePoint.stdin ? "-i " : "", - ...Object.entries(env).map(([key, val]) => ["-e", `${key}=${val}`]) - .flat(), - tag, - ]} ${ePoint.cmd}` - .env(env); - if (ePoint.stdin) { - cmd = cmd.stdinText(ePoint.stdin!); - } - try { - await cmd; - } catch (err) { - logger(import.meta).error(err); - throw err; - } - } - if (!noRmi) { - await $ - .raw`${dockerCmd} rmi '${tag}'` - .env(env); - } -} export async function localE2eTest(testCase: E2eTestCase) { - const { envVars: testEnvs, ePoints, tsGhjkfileStr } = testCase; + const { envVars: testEnvs, ePoints, fs } = testCase; const tmpDir = $.path( await Deno.makeTempDir({ prefix: "ghjk_le2e_", }), ); - const ghjkShareDir = await tmpDir.join("ghjk").ensureDir(); - - await tmpDir.join("ghjk.ts").writeText( - tsGhjkfileStr.replaceAll( - "$ghjk", - std_url.dirname(import.meta.resolve("../mod.ts")).href, - ), + const ghjkDataDir = await tmpDir.join("ghjk").ensureDir(); + + await $.co( + Object.entries(fs) + .map( + ([path, content]) => + tmpDir.join(path) + .writeText( + content.replaceAll( + "$ghjk", + std_url.dirname(import.meta.resolve("../mod.ts")).href, + ), + ), + ), ); - const env: Record = { - ...testEnvs, - BASH_ENV: `${ghjkShareDir.toString()}/env.bash`, - ZDOTDIR: ghjkShareDir.toString(), - GHJK_SHARE_DIR: ghjkShareDir.toString(), - PATH: `${ghjkShareDir.toString()}:${Deno.env.get("PATH")}`, + const ghjkExePath = $.path(import.meta.resolve("../target/debug/ghjk")); + const ghjkShimPath = await ghjkDataDir + .join("ghjk") + .writeText( + `#!/bin/sh +exec ${ghjkExePath.resolve().toString()} "$@"`, + { mode: 0o700 }, + ); + + const env: Record = { + GHJK_AUTO_HOOK: "true", + BASH_ENV: `${ghjkDataDir.toString()}/env.bash`, + ZDOTDIR: ghjkDataDir.toString(), + GHJK_DATA_DIR: ghjkDataDir.toString(), + PATH: `${ghjkShimPath.parentOrThrow().toString()}:${Deno.env.get("PATH")}`, HOME: tmpDir.toString(), + GHJK_REPO_ROOT: import.meta.resolve("../"), + // share the system's deno cache + GHJK_DENO_DIR: Deno.env.get("DENO_DIR") + ? $.path(Deno.env.get("DENO_DIR")!).resolve().toString() + : $.path(Deno.env.get("HOME")!).resolve(".cache", "deno").toString(), + RUST_LOG: Deno.env.get("RUST_LOG"), + GHJK_LOG: Deno.env.get("GHJK_LOG"), + ...testEnvs, }; // install ghjk await install({ ...defaultInstallArgs, - skipExecInstall: false, - ghjkExecInstallDir: ghjkShareDir.toString(), - // share the system's deno cache - ghjkDenoCacheDir: Deno.env.get("DENO_DIR") ?? - $.path(Deno.env.get("HOME")!).join(".cache", "deno").toString(), - ghjkShareDir: ghjkShareDir.toString(), + ghjkDataDir: ghjkDataDir.toString(), // don't modify system shell configs shellsToHook: [], }); - await $`${ghjkShareDir.join("ghjk").toString()} print config` + await $`ghjk print config` .cwd(tmpDir.toString()) .clearEnv() .env(env); - await $`${ghjkShareDir.join("ghjk").toString()} envs cook` + await $`ghjk envs cook` .cwd(tmpDir.toString()) .clearEnv() .env(env); /* // print the contents of the ghjk dir for debugging purposes const ghjkDirLen = ghjkDir.toString().length; - dbg((await Array.fromAsync(ghjkShareDir.walk())).map((entry) => [ + dbg((await Array.fromAsync(ghjkDataDir.walk())).map((entry) => [ entry.isDirectory ? "dir " : entry.isSymlink ? "ln " : "file", entry.path.toString().slice(ghjkDirLen), ])); */ { - const confHome = await ghjkShareDir.join(".config").ensureDir(); + const confHome = await tmpDir.join(".config").ensureDir(); const fishConfDir = await confHome.join("fish").ensureDir(); await fishConfDir.join("config.fish").symlinkTo( - ghjkShareDir.join("env.fish").toString(), + ghjkDataDir.join("env.fish").toString(), ); env["XDG_CONFIG_HOME"] = confHome.toString(); } @@ -232,17 +176,11 @@ export function harness( cases: E2eTestCase[], ) { const e2eType = Deno.env.get("GHJK_TEST_E2E_TYPE"); - let runners = [[dockerE2eTest, "e2eDocker" as string] as const]; - if (e2eType == "both") { - runners.push([localE2eTest, "e2eLocal"]); - } else if (e2eType == "local") { - runners = [[localE2eTest, "e2eLocal"]]; - } else if ( - e2eType && e2eType != "docker" - ) { - throw new Error( - `unexpected GHJK_TEST_E2E_TYPE: ${e2eType}`, - ); + const runners = [ + [localE2eTest, "e2eLocal"] as const, + ]; + if (e2eType && e2eType != "local") { + throw new Error("docker test runner has been removed"); } for (const [runner, group] of runners) { for (const testCase of cases) { diff --git a/tools/check.ts b/tools/check.ts new file mode 100755 index 00000000..1231afcb --- /dev/null +++ b/tools/check.ts @@ -0,0 +1,24 @@ +#!/bin/env -S ghjk deno run --allow-env --allow-run --allow-read --allow-write=. + +import "../setup_logger.ts"; +import { $ } from "../utils/mod.ts"; + +const files = (await Array.fromAsync( + $.path(import.meta.url).parentOrThrow().parentOrThrow().expandGlob( + "**/*.ts", + { + exclude: [ + ".git", + ".dev", + "play.ts", + ".ghjk/**", + ".deno-dir/**", + "vendor/**", + ".git/**", // was throwing an error without this + "target/", + ], + }, + ), +)).map((ref) => ref.path.toString()); + +await $`${Deno.env.get("DENO_EXEC_PATH") ?? "deno"} check ${files}`; diff --git a/tools/dev.ts b/tools/dev.ts new file mode 100755 index 00000000..d6e737c5 --- /dev/null +++ b/tools/dev.ts @@ -0,0 +1,78 @@ +#!/bin/env -S deno run -A + +//! Spawns the provided arguments within an environment +//! that contains a ghjk installation from the repo instead +//! of the gloabl ghjk installation + +import { defaultInstallArgs, install } from "../install/mod.ts"; +import { $ } from "../utils/mod.ts"; + +const devDir = $.path( + import.meta.dirname!, + // await Deno.makeTempDir({ + // prefix: "ghjk_le2e_", + // }), +).join("../.dev"); + +const ghjkDataDir = await devDir.join("ghjk").ensureDir(); + +await (await $.removeIfExists(devDir.join("ghjk.ts"))) + .symlinkTo(import.meta.resolve("../ghjk.ts")); + +const ghjkExePath = $.path(import.meta.resolve("../target/debug/ghjk")); +await ghjkDataDir + .join("ghjk") + .writeText( + `#!/bin/sh +exec ${ghjkExePath.resolve().toString()} "$@"`, + { mode: 0o700 }, + ); + +const env: Record = { + BASH_ENV: `${ghjkDataDir.toString()}/env.bash`, + ZDOTDIR: ghjkDataDir.toString(), + GHJK_DATA_DIR: ghjkDataDir.toString(), + PATH: `${ghjkDataDir.toString()}:${Deno.env.get("PATH")}`, + GHJK_CONFIG_DIR: devDir.toString(), + // HOME: devDir.toString(), +}; + +await devDir.join("config.json").writeJsonPretty({ + "data_dir": ghjkDataDir.toString(), +}); + +// install ghjk +await install({ + ...defaultInstallArgs, + ghjkDataDir: ghjkDataDir.toString(), + // don't modify system shell configs + shellsToHook: [], +}); + +// await $`${ghjkDataDir.join("ghjk").toString()} print config` +// .cwd(devDir.toString()) +// .clearEnv() +// .env(env); +// +// await $`${ghjkDataDir.join("ghjk").toString()} envs cook` +// .cwd(devDir.toString()) +// .clearEnv() +// .env(env); +let cmd; +if (Deno.args.length) { + if (Deno.args[0] == "bash" && Deno.args.length == 1) { + cmd = $`bash --rcfile ${env.BASH_ENV}`; + } else if (Deno.args[0] == "fish" && Deno.args.length == 1) { + // cmd = $`fish --no-config --init-command 'source ${ + cmd = $`fish --init-command 'source ${ + ghjkDataDir.join("env.fish").toString() + }'`; + } else { + cmd = $`${Deno.args}`; + } +} else { + throw new Error("shell program arg expected"); +} + +await cmd.env(env).noThrow() + .cwd(Deno.env.get("CWD") ?? Deno.cwd()); diff --git a/utils/logger.ts b/utils/logger.ts index e6382011..6415647f 100644 --- a/utils/logger.ts +++ b/utils/logger.ts @@ -1,3 +1,5 @@ +// care needed in importing items here since this is a common +// import file import { std_fmt_colors, std_log, @@ -105,7 +107,7 @@ export class TestConsoleErrHandler extends ConsoleErrHandler { super(levelName, options); } - handle(lr: std_log.LogRecord): void { + override handle(lr: std_log.LogRecord): void { if (lr.level >= this.throwLevel) { throw new Error(`detected ${lr.levelName} log record:`, { cause: lr }); } @@ -140,6 +142,7 @@ export default function logger( logger = new std_log.Logger(name, level, { handlers: [consoleHandler], }); + loggers.set(name, logger); } return logger; } diff --git a/utils/mod.ts b/utils/mod.ts index 8dfb4c0a..464a43df 100644 --- a/utils/mod.ts +++ b/utils/mod.ts @@ -43,7 +43,7 @@ export const jsonSchema: zod.ZodType = zod.lazy(() => ); export function dbg(val: T, ...more: unknown[]) { - logger().debug(() => val, ...more, "DBG"); + logger().debug("DBG", val, ...more); return val; } @@ -250,11 +250,12 @@ export const $ = dax.build$( depth: 10, }); }, - co( + co: ((values: any[]) => Promise.all(values)) as typeof Promise.all, + /* co( values: T, ): Promise<{ -readonly [P in keyof T]: Awaited }> { return Promise.all(values); - }, + }, */ // coIter( // items: Iterable, // fn: (item:T) => PromiseLike, @@ -281,6 +282,7 @@ export const $ = dax.build$( } return pathRef; }, + dbg, }, }, ); @@ -290,7 +292,7 @@ export function inWorker() { self instanceof WorkerGlobalScope; } -export async function findEntryRecursive(path: string, name: string) { +export async function findEntryRecursive(path: string | Path, name: string) { let current = $.path(path); while (true) { const location = `${current}/${name}`; @@ -305,29 +307,6 @@ export async function findEntryRecursive(path: string, name: string) { } } -export function homeDir() { - switch (Deno.build.os) { - case "linux": - case "darwin": - return Deno.env.get("HOME") ?? null; - case "windows": - return Deno.env.get("USERPROFILE") ?? null; - default: - return null; - } -} - -export function dirs() { - const home = homeDir(); - if (!home) { - throw new Error("cannot find home dir"); - } - return { - homeDir: home, - shareDir: $.path(home).resolve(".local", "share"), - }; -} - export const AVAIL_CONCURRENCY = Number.parseInt( Deno.env.get("DENO_JOBS") ?? "1", ); @@ -409,6 +388,7 @@ export type DownloadFileArgs = { export async function downloadFile( args: DownloadFileArgs, ) { + logger().debug("downloading", args); const { name, mode, url, downloadPath, tmpDirPath, headers } = { name: $.path(args.url).basename(), mode: 0o666, @@ -542,33 +522,37 @@ export function thinInstallConfig(fat: InstallConfigFat) { export type OrRetOf = T extends () => infer Inner ? Inner : T; +/** + * This tries to emulate a rust `match` statement but in a typesafe + * way. This is a WIP function. + * ```ts + * const pick: 2 = switchMap( + * "hello", + * { + * hey: () => 1, + * hello: () => 2, + * hi: 3, + * holla: 4, + * }, + * ); + * ``` + */ export function switchMap< K extends string | number | symbol, All extends { - [Key in K]: All[K]; + [Key in K]?: All[K]; }, ->( +> // D = undefined, +( val: K, branches: All, - // def?: D, + // def?: (val: K) => D, ): K extends keyof All ? OrRetOf - : /* All[keyof All] | */ undefined { - // return branches[val]; + : OrRetOf | undefined { const branch = branches[val]; return typeof branch == "function" ? branch() : branch; } -switchMap( - "holla" as string, - { - hey: () => 1, - hello: () => 2, - hi: 3, - holla: 4, - } as const, - // () =>5 -); - export async function expandGlobsAndAbsolutize( path: string, wd: string, @@ -597,13 +581,12 @@ export function unwrapZodRes( const zodErr = zod_val_err.fromZodError(res.error, { includePath: true, maxIssuesInMessage: 3, + prefix: errMessage, }); - throw new Error(`${errMessage}: ${zodErr}`, { - cause: { - issues: res.error.issues, - ...cause, - }, - }); + zodErr.cause = { + ...cause, + }; + throw zodErr; } return res.data; } diff --git a/utils/unarchive.ts b/utils/unarchive.ts index 4ff3b3fb..cbc2b5bc 100644 --- a/utils/unarchive.ts +++ b/utils/unarchive.ts @@ -4,7 +4,6 @@ import { std_fs, std_io, std_path, - std_streams, std_untar, } from "../deps/ports.ts"; @@ -45,7 +44,7 @@ export async function untgz( await Foras.initBundledOnce(); const tgzFile = await Deno.open(path, { read: true }); const gzDec = new Foras.GzDecoder(); - await std_streams.copy(tgzFile, { + await std_io.copy(tgzFile, { write(buf) { const mem = new Foras.Memory(buf); gzDec.write(mem); @@ -77,7 +76,7 @@ export async function untar( * This does not close the reader. */ export async function untarReader( - reader: Deno.Reader, + reader: std_io.Reader, dest = "./", ) { for await (const entry of new std_untar.Untar(reader)) { @@ -93,7 +92,7 @@ export async function untarReader( write: true, mode: entry.fileMode, }); - await std_streams.copy(entry, file); + await std_io.copy(entry, file); file.close(); } }