From 4497bd1fb4a3dd69482b362b47d826b8f8d5e7b5 Mon Sep 17 00:00:00 2001 From: Yohe-Am <56622350+Yohe-Am@users.noreply.github.com> Date: Wed, 4 Dec 2024 00:56:27 +0300 Subject: [PATCH 01/13] fix: deno X tokio issues --- .ghjk/deno.lock | 176 ++++++++-------- .ghjk/lock.json | 26 +-- .gitignore | 2 + Cargo.lock | 16 ++ ghjk.ts | 2 +- host/mod.ts | 4 +- modules/envs/mod.ts | 175 +++++++++++++++- modules/mod.ts | 4 +- modules/ports/mod.ts | 6 +- modules/tasks/mod.ts | 6 +- src/deno_systems/bindings.ts | 97 ++++++--- src/deno_systems/mod.ts | 2 +- src/deno_systems/types.ts | 130 ++++++++++++ src/denort/lib.rs | 175 ++++++++-------- src/ghjk/cli.rs | 391 +++++++++++++++++++++++++++++++++++ src/ghjk/ext.rs | 6 +- src/ghjk/ext/callbacks.rs | 53 ++--- src/ghjk/host.rs | 57 +++-- src/ghjk/host/hashfile.rs | 77 +++++-- src/ghjk/js/00_runtime.js | 4 +- src/ghjk/js/runtime.js | 9 +- src/ghjk/log.rs | 12 +- src/ghjk/main.rs | 149 +------------ src/ghjk/systems.rs | 43 +++- src/ghjk/systems/deno.rs | 41 +++- src/ghjk/systems/deno/cli.rs | 321 ++++++++++++++++++++++++++++ src/ghjk/utils.rs | 36 +++- src/play/Cargo.toml | 22 ++ src/play/main.rs | 20 ++ src/xtask/main.rs | 9 + 30 files changed, 1601 insertions(+), 470 deletions(-) create mode 100644 src/deno_systems/types.ts create mode 100644 src/ghjk/cli.rs create mode 100644 src/ghjk/systems/deno/cli.rs create mode 100644 src/play/Cargo.toml create mode 100644 src/play/main.rs diff --git a/.ghjk/deno.lock b/.ghjk/deno.lock index fbcc951..98d050b 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": { diff --git a/.ghjk/lock.json b/.ghjk/lock.json index 410bbd9..0e9eb94 100644 --- a/.ghjk/lock.json +++ b/.ghjk/lock.json @@ -308,13 +308,13 @@ "lock-sed": { "ty": "denoFile@v1", "key": "lock-sed", - "envKey": "bciqlneazfye2nq2cb4jsgigjqisrzm25gdkyitmotyl3qmq5nf3nb7y" + "envKey": "bciqpstuhgkq5ne5uv4wobyf2houlb2leq5uvhevfmkr7rqudwro2f6i" }, "cache-v8": { "ty": "denoFile@v1", "key": "cache-v8", "desc": "Install the V8 builds to a local cache.", - "envKey": "bciqe5yq32fnpsioc326yny37wl3jszc6sgq3imo6544ez7iswpu3yny" + "envKey": "bciqksijm3dibc72cqwbp7e6chayqnuhvpzj24ev6zzsjhn3bmt6copq" } }, "tasksNamed": [ @@ -327,13 +327,13 @@ "id": "envs", "config": { "envs": { - "bciqazjf2gsxfy4wt2gd6qsou4pciedy7dyhdch5l7gsmoq62boo2s7a": { + "bciqjpw6xgc3ajnko2ymjuapnthfzgifz4yacuw62zjx4t6w2ya55mda": { "desc": "the default default environment.", "provides": [ { "ty": "posix.envVar", "key": "RUST_LOG", - "val": "trace,deno=info,denort=trace,swc_ecma_transforms_base=info" + "val": "debug,deno=info,denort=trace,swc_ecma_transforms_base=info" }, { "ty": "ghjk.ports.InstallSetRef", @@ -341,12 +341,12 @@ } ] }, - "bciqlneazfye2nq2cb4jsgigjqisrzm25gdkyitmotyl3qmq5nf3nb7y": { + "bciqpstuhgkq5ne5uv4wobyf2houlb2leq5uvhevfmkr7rqudwro2f6i": { "provides": [ { "ty": "posix.envVar", "key": "RUST_LOG", - "val": "trace,deno=info,denort=trace,swc_ecma_transforms_base=info" + "val": "debug,deno=info,denort=trace,swc_ecma_transforms_base=info" }, { "ty": "ghjk.ports.InstallSetRef", @@ -354,12 +354,12 @@ } ] }, - "bciqe5yq32fnpsioc326yny37wl3jszc6sgq3imo6544ez7iswpu3yny": { + "bciqksijm3dibc72cqwbp7e6chayqnuhvpzj24ev6zzsjhn3bmt6copq": { "provides": [ { "ty": "posix.envVar", "key": "RUST_LOG", - "val": "trace,deno=info,denort=trace,swc_ecma_transforms_base=info" + "val": "debug,deno=info,denort=trace,swc_ecma_transforms_base=info" }, { "ty": "ghjk.ports.InstallSetRef", @@ -367,12 +367,12 @@ } ] }, - "bciqe26fbb6fkfbou7w3rf3t2uqw4neldvakclhcecktgtpcuxwnzgja": { + "bciqh3i5r22rdn63dpluzbp7buhz5ko2jsyarp3nlet2kqzypdfpmlqi": { "provides": [ { "ty": "posix.envVar", "key": "RUST_LOG", - "val": "trace,deno=info,denort=trace,swc_ecma_transforms_base=info" + "val": "debug,deno=info,denort=trace,swc_ecma_transforms_base=info" }, { "ty": "posix.envVar", @@ -388,9 +388,9 @@ }, "defaultEnv": "dev", "envsNamed": { - "main": "bciqazjf2gsxfy4wt2gd6qsou4pciedy7dyhdch5l7gsmoq62boo2s7a", - "_rust": "bciqe5yq32fnpsioc326yny37wl3jszc6sgq3imo6544ez7iswpu3yny", - "dev": "bciqe26fbb6fkfbou7w3rf3t2uqw4neldvakclhcecktgtpcuxwnzgja" + "main": "bciqjpw6xgc3ajnko2ymjuapnthfzgifz4yacuw62zjx4t6w2ya55mda", + "_rust": "bciqksijm3dibc72cqwbp7e6chayqnuhvpzj24ev6zzsjhn3bmt6copq", + "dev": "bciqh3i5r22rdn63dpluzbp7buhz5ko2jsyarp3nlet2kqzypdfpmlqi" } } } diff --git a/.gitignore b/.gitignore index ffa470c..269d8a0 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,8 @@ deno.land jsr.io esm.sh +src/play/*.rs + # Added by cargo /target diff --git a/Cargo.lock b/Cargo.lock index 421172d..20c5d2f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5457,6 +5457,22 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +[[package]] +name = "play" +version = "0.3.0" +dependencies = [ + "clap", + "color-eyre", + "data-encoding", + "futures-concurrency", + "once_cell", + "sha2", + "tokio", + "tracing", + "tracing-subscriber", + "tracing-unwrap", +] + [[package]] name = "png" version = "0.17.13" diff --git a/ghjk.ts b/ghjk.ts index 3b0c45f..065fe27 100644 --- a/ghjk.ts +++ b/ghjk.ts @@ -15,7 +15,7 @@ config({ }); env("main").vars({ - RUST_LOG: "trace,deno=info,denort=trace,swc_ecma_transforms_base=info", + RUST_LOG: "debug,deno=info,denort=trace,swc_ecma_transforms_base=info", }); env("_rust") diff --git a/host/mod.ts b/host/mod.ts index 651a9b8..c4b2315 100644 --- a/host/mod.ts +++ b/host/mod.ts @@ -157,7 +157,9 @@ export async function cli(args: CliArgs) { .command( "ghjkdir-path", new cliffy_cmd.Command() - .description("Print the path where ghjk is installed in.") + .description( + "Print the path to the dir of the currently active ghjk context.", + ) .action(function () { if (!gcx) { throw new Error("no ghjkfile found."); diff --git a/modules/envs/mod.ts b/modules/envs/mod.ts index d15d706..fd24b0e 100644 --- a/modules/envs/mod.ts +++ b/modules/envs/mod.ts @@ -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; @@ -34,7 +35,7 @@ const lockValidator = zod.object({ type EnvsLockEnt = zod.infer; export class EnvsModule extends ModuleBase { - loadConfig( + override loadConfig( manifest: ModuleManifest, _bb: Blackboard, _lockEnt: EnvsLockEnt | undefined, @@ -59,7 +60,177 @@ export class EnvsModule extends ModuleBase { } } - commands() { + override commands(): CliCommand[] { + const gcx = this.gcx; + const ecx = getEnvsCtx(this.gcx); + + function envKeyArgs( + args: { + taskKeyMaybe?: string; + envKeyMaybe?: string; + }, + ) { + const { envKeyMaybe, taskKeyMaybe } = args; + if (taskKeyMaybe && envKeyMaybe) { + throw new Error( + "--task-env option can not be combined with [envName] argument", + ); + } + if (taskKeyMaybe) { + const tasksCx = getTasksCtx(gcx); + const taskDef = tasksCx.config.tasks[taskKeyMaybe]; + if (!taskDef) { + throw new Error(`no task found under key "${taskKeyMaybe}"`); + } + return { envKey: taskDef.envKey }; + } + const actualKey = ecx.config.envsNamed[envKeyMaybe ?? ecx.activeEnv]; + return actualKey + ? { envKey: actualKey, envName: envKeyMaybe ?? ecx.activeEnv } + : { envKey: envKeyMaybe ?? ecx.activeEnv }; + } + + const commonFlags = { + taskEnv: { + value_name: "taskName", + help: "Activate the environment used by the named task", + exclusive: true, + }, + }; + + const commonArgs = { + envKey: { + value_name: "envKey", + }, + }; + + return [ + { + name: "envs", + 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) + // envs that have names which start with underscors + // don't show up in the cli list + .filter(([key]) => !key.startsWith("_")) + .map(([name, hash]) => { + const { desc } = ecx.config.envs[hash]; + return `${name}${desc ? ": " + desc : ""}`; + }) + .join("\n"), + ); + }, + }, + { + name: "activate", + about: `Activate an environment.`, + before_long_help: + `- If no [envName] 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 }, args: { envName: envKeyMaybe } }, + ) { + const { envKey } = envKeyArgs({ + taskKeyMaybe: taskEnv, + envKeyMaybe, + }); + await activateEnv(envKey); + }, + }, + { + name: "cook", + about: `Cooks the environment to a posix shell.`, + before_long_help: + `- If no [envName] is specified, this will cook the active env [${ecx.activeEnv}]`, + flags: { + ...commonFlags, + }, + args: { + ...commonArgs, + }, + action: async function ( + { flags: { taskEnv }, args: { envName: envKeyMaybe } }, + ) { + const { envKey, envName } = envKeyArgs({ + taskKeyMaybe: taskEnv, + envKeyMaybe, + }); + await reduceAndCookEnv(gcx, ecx, envKey, envName ?? envKey); + }, + }, + { + 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}].`, + flags: { + ...commonFlags, + }, + args: { + ...commonArgs, + }, + action: async function ( + { flags: { taskEnv }, args: { envName: envKeyMaybe } }, + ) { + const { envKey } = envKeyArgs({ + taskKeyMaybe: taskEnv, + envKeyMaybe, + }); + const env = ecx.config.envs[envKey]; + if (!env) { + throw new Error(`no env found under "${envKey}"`); + } + // deno-lint-ignore no-console + console.log($.inspect(await showableEnv(gcx, env, envKey))); + }, + }, + ], + }, + { + name: "sync", + about: "Synchronize your shell to what's in your config.", + before_long_help: `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.`, + flags: { + ...commonFlags, + }, + args: { + ...commonArgs, + }, + action: async function ( + { flags: { taskEnv }, args: { envName: envKeyMaybe } }, + ) { + const { envKey, envName } = envKeyArgs({ + taskKeyMaybe: taskEnv, + envKeyMaybe, + }); + await reduceAndCookEnv( + gcx, + ecx, + envKey, + envName ?? envKey, + ); + await activateEnv(envKey); + }, + }, + ]; + } + commands2() { const gcx = this.gcx; const ecx = getEnvsCtx(this.gcx); diff --git a/modules/mod.ts b/modules/mod.ts index 9ec8165..210079a 100644 --- a/modules/mod.ts +++ b/modules/mod.ts @@ -1,5 +1,5 @@ -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"; @@ -18,5 +18,5 @@ export abstract class ModuleBase { raw: Json, ): Promise | LockEnt | undefined; abstract genLockEntry(): Promise | Json; - abstract commands(): Record>; + abstract commands(): CliCommand[]; } diff --git a/modules/ports/mod.ts b/modules/ports/mod.ts index 9211346..811d09e 100644 --- a/modules/ports/mod.ts +++ b/modules/ports/mod.ts @@ -110,7 +110,11 @@ export class PortsModule extends ModuleBase { ); } - commands() { + override commands() { + return []; + } + + commands2() { const gcx = this.gcx; const pcx = getPortsCtx(gcx); diff --git a/modules/tasks/mod.ts b/modules/tasks/mod.ts index 7bdb2a2..62ac0c1 100644 --- a/modules/tasks/mod.ts +++ b/modules/tasks/mod.ts @@ -46,7 +46,11 @@ export class TasksModule extends ModuleBase { tcx.taskGraph = taskGraph; } - commands() { + override commands() { + return []; + } + + commands2() { const gcx = this.gcx; const tcx = getTasksCtx(this.gcx); diff --git a/src/deno_systems/bindings.ts b/src/deno_systems/bindings.ts index bbfd0e3..f53cbb3 100644 --- a/src/deno_systems/bindings.ts +++ b/src/deno_systems/bindings.ts @@ -1,10 +1,26 @@ // import "../../src/ghjk/js/mock.sfx.ts"; import { zod } from "../../deps/common.ts"; -import { $, Json, unwrapZodRes } from "../../utils/mod.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 } from "../ghjk/js/runtime.js"; +import { Ghjk, Json } from "../ghjk/js/runtime.js"; + +import type { + CliCommand, + CliCommandBindedX, + DenoSystemsRoot, +} from "./types.ts"; +import bindingTypes from "./types.ts"; + +// start an interval to prevent the event loop exiting +// after loading systems +setInterval(() => {/* beat */}, 1000); +// 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(), @@ -15,25 +31,8 @@ const prepareArgs = zod.object({ }), }); -const denoSystemsRoot = zod.object({ - systems: zod.record(zod.function()), -}); - -type DenoSystemCtor = (gcx: GhjkCtx) => ModuleBase; - -export type DenoSystemsRoot = { - systems: Record; -}; - -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; -}; +const args = prepareArgs.parse(Ghjk.blackboard.get("args")); +await prepareSystems(args); async function prepareSystems(args: zod.infer) { const gcx = { @@ -47,7 +46,7 @@ async function prepareSystems(args: zod.infer) { const { default: mod } = await import(args.uri); const { systems } = unwrapZodRes( - denoSystemsRoot.safeParse(mod), + bindingTypes.denoSystemsRoot.safeParse(mod), ) as DenoSystemsRoot; const manifests = [] as ManifestDesc[]; @@ -67,6 +66,18 @@ async function prepareSystems(args: zod.infer) { 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, @@ -110,17 +121,37 @@ function instanceBinding( 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; } -// start an interval to prevent the event loop exiting -// after loading systems -setInterval(() => {/* beat */}, 1000); -// FIXME: better means of exit detection, keep alive as long -// as callbacks are registered? -// globalThis.onbeforeunload = (evt) => { -// evt.preventDefault(); -// }; - -const args = prepareArgs.parse(Ghjk.blackboard.get("args")); -await prepareSystems(args); +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 index ddfcea4..92e4531 100644 --- a/src/deno_systems/mod.ts +++ b/src/deno_systems/mod.ts @@ -1,5 +1,5 @@ import { map } from "../../modules/std.ts"; -import type { DenoSystemsRoot } from "./bindings.ts"; +import type { DenoSystemsRoot } from "./types.ts"; export default { systems: Object.fromEntries( diff --git a/src/deno_systems/types.ts b/src/deno_systems/types.ts new file mode 100644 index 0000000..6e8b1f3 --- /dev/null +++ b/src/deno_systems/types.ts @@ -0,0 +1,130 @@ +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(), + + required: zod.boolean().optional(), + global: zod.boolean().optional(), + hide: zod.boolean().optional(), + exclusive: 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(), + + short_flag: charSchema.optional(), + aliases: zod.string().array().optional(), + visible_aliases: zod.string().array().optional(), + + hide: zod.boolean().optional(), + + about: zod.string().optional(), + before_help: zod.string().optional(), + before_long_help: zod.string().optional(), + + args: zod.record(cliArg).optional().optional(), + flags: zod.record(cliFlag).optional().optional(), +}); + +const cliActionArgs = zod.object({ + flags: zod.record(zod.string().optional()), + args: zod.record(zod.string().optional()), +}); + +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 CommandAction = ( + args: { + flags: Record; + args: Record; + }, +) => Promise | void; + +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/lib.rs b/src/denort/lib.rs index e7ab513..b84d8f7 100644 --- a/src/denort/lib.rs +++ b/src/denort/lib.rs @@ -29,7 +29,6 @@ use deno::{ }, *, }; -use std::sync::atomic::AtomicBool; #[rustfmt::skip] use deno_runtime::deno_core as deno_core; // necessary for re-exported macros to work @@ -63,59 +62,57 @@ pub async fn worker( ) -> Res { let cx = WorkerContext::from_config(flags, custom_extensions_cb).await?; - let (tx, mut rx) = tokio::sync::mpsc::unbounded_channel::(); - let rt = tokio::runtime::Handle::current(); - - let term_signal = AtomicBool::new(false); - let term_signal = Arc::new(term_signal); - - let global_term_signal = term_signal.clone(); - let join_handle = new_thread_builder() - .name(WORKER_THREAD_NAME.into()) - .spawn(move || { - let local = tokio::task::LocalSet::new(); - - local.spawn_local( - async move { - debug!("starting deno worker"); - while let Some(msg) = rx.recv().await { - debug!(?msg, "deno worker msg"); - match msg { - DenoWorkerMsg::PrepareModule { - response_channel, - inner, - } => { - response_channel - .send( - module_worker(&cx, global_term_signal.clone(), inner).await, - ) - .expect_or_log("channel error"); - } - } + let (msg_tx, mut msg_rx) = tokio::sync::mpsc::unbounded_channel::(); + + let (term_signal_tx, mut term_signal_rx) = tokio::sync::watch::channel(false); + + let join_handle = deno_core::unsync::spawn( + async move { + trace!("starting deno worker"); + loop { + let msg = tokio::select! { + Some(msg) = msg_rx.recv() => { + msg + } + _ = term_signal_rx.changed() => break, + else => break + }; + trace!(?msg, "deno worker msg"); + match msg { + DenoWorkerMsg::PrepareModule { + response_channel, + inner, + } => { + response_channel + .send(module_worker(&cx, term_signal_rx.clone(), inner).await) + .expect_or_log("channel error"); } - debug!("deno worker done"); } - .instrument(tracing::debug_span!("deno-worker")), - ); - rt.block_on(local); - }) - .unwrap(); + } + 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: tx, - term_signal, + sender: msg_tx, + term_signal: term_signal_tx, join_handle, }) } +type TermSignal = tokio::sync::watch::Receiver; + async fn module_worker( cx: &WorkerContext, - global_term_signal: Arc, + global_term_signal: TermSignal, msg: PrepareModuleMsg, ) -> Res { let mut module_cx = cx .prepare_module( - msg.main_module, + msg.main_module.clone(), &msg.permissions, msg.mode, msg.stdio, @@ -124,16 +121,16 @@ async fn module_worker( .await?; let (module_tx, mut module_rx) = tokio::sync::mpsc::channel::(1); - tokio::task::spawn_local( + deno_core::unsync::spawn( async move { - debug!("starting module worker"); + trace!("starting module worker"); while let Some(msg) = module_rx.recv().await { - debug!(?msg, "module worker msg"); + trace!(?msg, "module worker msg"); match msg { ModuleWorkerReq::Run { response_channel } => response_channel .send( module_cx - .run(&global_term_signal) + .run(global_term_signal.clone()) .await .map_err(|err| ferr!(Box::new(err))), ) @@ -144,7 +141,7 @@ async fn module_worker( } => response_channel .send( module_cx - .drive_till_exit(&global_term_signal, &term_signal) + .drive_till_exit(global_term_signal.clone(), term_signal) .await .map_err(|err| ferr!(Box::new(err))), ) @@ -162,9 +159,13 @@ async fn module_worker( .expect_or_log("channel error"), } } - debug!("module worker done"); + std::mem::forget(module_cx); + trace!("module worker done"); } - .instrument(tracing::debug_span!("deno-module-worker")), + .instrument(tracing::trace_span!( + "deno-module-worker", + main_module = %msg.main_module + )), ); Ok(ModuleWorkerHandle { sender: module_tx }) } @@ -288,25 +289,26 @@ enum DenoWorkerMsg { }, } -#[derive(Clone, Debug)] +#[derive(Clone, educe::Educe)] +#[educe(Debug)] pub struct DenoWorkerHandle { sender: tokio::sync::mpsc::UnboundedSender, - join_handle: Arc>>>, - term_signal: Arc, + term_signal: tokio::sync::watch::Sender, + #[educe(Debug(ignore))] + join_handle: Arc>>>, } impl DenoWorkerHandle { - pub fn terminate(self) { - self.term_signal - .store(true, std::sync::atomic::Ordering::Relaxed); + pub async fn terminate(self) -> Res<()> { + self.term_signal.send(true)?; 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; + return Ok(()); }; - join_handle.join().expect_or_log("join error") + join_handle.await.wrap_err("tokio error") } } @@ -367,17 +369,19 @@ impl ModuleWorkerContext { .collect() } - async fn run(&mut self, global_term_signal: &AtomicBool) -> anyhow::Result { + async fn run(&mut self, global_term_signal: TermSignal) -> anyhow::Result { debug!("main_module {}", self.main_module); self.execute_main_module().await?; - self.drive_till_exit(global_term_signal, &AtomicBool::new(false)) + + let (_local_signal_tx, local_signal_rx) = tokio::sync::watch::channel(false); + self.drive_till_exit(global_term_signal, local_signal_rx) .await } async fn drive_till_exit( &mut self, - global_term_signal: &AtomicBool, - term_signal: &AtomicBool, + mut global_term_signal: TermSignal, + mut term_signal: TermSignal, ) -> anyhow::Result { self.worker.dispatch_load_event()?; loop { @@ -406,20 +410,26 @@ impl ModuleWorkerContext { .run_event_loop(self.maybe_coverage_collector.is_none()) .await?; } */ + + let event_loop_future = self.worker.run_event_loop(false).boxed_local(); + + tokio::select! { + _ = global_term_signal.changed() => { + trace!("global term signal lit, shutting down event loop"); + break + }, + _ = term_signal.changed() => { + trace!("worker term signal lit, shutting down event loop"); + break + }, + event_loop_result = event_loop_future => { + event_loop_result? + } + }; self.worker .run_event_loop(self.maybe_coverage_collector.is_none()) .await?; - if term_signal.load(std::sync::atomic::Ordering::Relaxed) { - trace!("worker term signal lit, shutting down event loop"); - break; - } - - if global_term_signal.load(std::sync::atomic::Ordering::Relaxed) { - trace!("globalterm signal lit, shutting down event loop"); - break; - } - let web_continue = self.worker.dispatch_beforeunload_event()?; if !web_continue { let node_continue = self.worker.dispatch_process_beforeexit_event()?; @@ -467,8 +477,7 @@ enum ModuleWorkerReq { response_channel: tokio::sync::oneshot::Sender>, }, DriveTillExit { - #[educe(Debug(ignore))] - term_signal: Arc, + term_signal: TermSignal, #[educe(Debug(ignore))] response_channel: tokio::sync::oneshot::Sender>, }, @@ -527,28 +536,28 @@ impl ModuleWorkerHandle { } /// Drive the event loop until exit and return - /// result in returned channel. + /// 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<( tokio::sync::oneshot::Receiver>, - Arc, + tokio::sync::watch::Sender, FinishedWorkerHandle, )> { - let term_signal = AtomicBool::new(false); - let term_signal = Arc::new(term_signal); + let (term_signal_tx, term_signal_rx) = tokio::sync::watch::channel(false); let (tx, rx) = tokio::sync::oneshot::channel(); self.sender .send(ModuleWorkerReq::DriveTillExit { - term_signal: term_signal.clone(), + term_signal: term_signal_rx, response_channel: tx, }) .await .expect_or_log("channel error"); Ok(( rx, - term_signal, + term_signal_tx, FinishedWorkerHandle { sender: self.sender, }, @@ -580,7 +589,7 @@ fn spawn_subcommand + 'static>(f: F) -> JoinHandle<()> { } pub fn run_sync( main_mod: ModuleSpecifier, - import_map_url: Option, + config_file: Option, permissions: args::PermissionFlags, custom_extensions: Arc, ) { @@ -588,7 +597,7 @@ pub fn run_sync( .spawn(|| { create_and_run_current_thread_with_maybe_metrics(async move { spawn_subcommand(async move { - run(main_mod, import_map_url, permissions, custom_extensions) + run(main_mod, config_file, permissions, custom_extensions) .await .unwrap() }) @@ -603,7 +612,7 @@ pub fn run_sync( pub async fn run( main_module: ModuleSpecifier, - import_map_url: Option, + config_file: Option, permissions: args::PermissionFlags, custom_extensions: Arc, ) -> anyhow::Result<()> { @@ -611,7 +620,6 @@ pub async fn run( // as it breaks our custom_extensions patch for some reason let flags = args::Flags { permissions, - import_map_path: import_map_url, unstable_config: args::UnstableConfig { features: DEFAULT_UNSTABLE_FLAGS .iter() @@ -620,6 +628,11 @@ pub async fn run( .collect(), ..Default::default() }, + config_flag: if let Some(config_file) = config_file { + args::ConfigFlag::Path(config_file) + } else { + Default::default() + }, ..Default::default() }; diff --git a/src/ghjk/cli.rs b/src/ghjk/cli.rs new file mode 100644 index 0000000..88bdd51 --- /dev/null +++ b/src/ghjk/cli.rs @@ -0,0 +1,391 @@ +use crate::interlude::*; + +use crate::systems::{CliCommandAction, SystemCliCommand}; +use crate::{host, systems, utils, Config}; + +const DENO_UNSTABLE_FLAGS: &[&str] = &["worker-options", "kv"]; + +pub async fn cli() -> Res<()> { + let cwd = std::env::current_dir()?; + + let config = { + let ghjk_dir_path = match std::env::var("GHJK_DIR") { + Ok(path) => Some(PathBuf::from(path)), + Err(std::env::VarError::NotUnicode(os_str)) => Some(PathBuf::from(os_str)), + Err(std::env::VarError::NotPresent) => { + utils::find_entry_recursive(&cwd, ".ghjk").await? + } + }; + + let ghjk_dir_path = if let Some(path) = ghjk_dir_path { + Some(tokio::fs::canonicalize(path).await?) + } else { + None + }; + + let ghjkfile_path = match &ghjk_dir_path { + Some(ghjkfile_path) => { + utils::find_entry_recursive( + ghjkfile_path + .parent() + .expect_or_log("invalid GHJK_DIR path"), + "ghjk.ts", + ) + .await? + } + None => utils::find_entry_recursive(&cwd, "ghjk.ts").await?, + }; + + let ghjkfile_path = if let Some(path) = ghjkfile_path { + Some(tokio::fs::canonicalize(path).await?) + } else { + None + }; + + if ghjk_dir_path.is_none() && ghjkfile_path.is_none() { + warn!( + "ghjk could not find any ghjkfiles or ghjkdirs, try creating a `ghjk.ts` script.", + ); + } + + let share_dir_path = match std::env::var("GHJK_SHARE_DIR") { + Ok(path) => PathBuf::from(path), + Err(std::env::VarError::NotUnicode(os_str)) => PathBuf::from(os_str), + Err(std::env::VarError::NotPresent) => directories::BaseDirs::new() + .expect_or_log("unable to resolve home dir") + .data_local_dir() + .join("ghjk"), + }; + Config { + ghjkfile_path, + ghjkdir_path: ghjk_dir_path, + share_dir_path, + } + }; + + let Some(quick_err) = try_quick_cli(&config).await? else { + return Ok(()); + }; + + let Some(ghjk_dir_path) = config.ghjkdir_path.clone() else { + quick_err.exit(); + }; + + let deno_cx = denort::worker( + denort::deno::args::Flags { + unstable_config: denort::deno::args::UnstableConfig { + features: DENO_UNSTABLE_FLAGS + .iter() + .copied() + .map(String::from) + .collect(), + ..default() + }, + ..default() + }, + Some(Arc::new(Vec::new)), + ) + .await?; + + let gcx = GhjkCtx { + ghjk_dir_path, + ghjkfile_path: config.ghjkfile_path.clone(), + share_dir_path: config.share_dir_path.clone(), + repo_root: url::Url::from_file_path(&cwd) + .expect_or_log("cwd error") + // repo root url must end in slash due to + // how Url::join works + .join(&format!("{}/", cwd.file_name().unwrap().to_string_lossy())) + .wrap_err("repo url error")?, + deno: deno_cx.clone(), + }; + let gcx = Arc::new(gcx); + + let systems_deno = systems::deno::systems_from_deno( + &gcx, + &gcx.repo_root + .join("src/deno_systems/mod.ts") + .wrap_err("repo url error")?, + ) + .await?; + + let hcx = host::HostCtx::new( + gcx, + host::Config { + re_resolve: false, + locked: false, + re_serialize: false, + env_vars: std::env::vars().collect(), + cwd, + }, + systems_deno, + ); + + let hcx = Arc::new(hcx); + + let Some(mut systems) = host::systems_from_ghjkfile(hcx).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!("colleting 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); + } + + 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(&config, Some(&systems.config))?; + return Ok(()); + } + 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); + } + }; + + let Some(action) = action.action else { + action.clap.print_long_help()?; + systems.write_lockfile_or_log().await; + return Ok(()); + }; + + let res = action(action_matches.clone()) + .await + .wrap_err_with(|| format!("errror on system command at path {cmd_path:?}")); + + systems.write_lockfile_or_log().await; + + deno_cx.terminate().await?; + + res +} + +/// 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, + ))); + } + } + } + + Ok(None) +} + +#[derive(clap::Parser, Debug)] +#[command(version, about)] +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, + }, +} + +#[derive(clap::Subcommand, Debug)] +enum PrintCommands { + /// Print the path where ghjk is installed in. + ShareDirPath, + /// 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::ShareDirPath => { + println!("{}", cli_config.share_dir_path.display()); + true + } + // TODO: rename GHJK_DIR to GHJKDIR + PrintCommands::GhjkdirPath => { + if let Some(path) = &cli_config.ghjkdir_path { + // TODO: graceful termination on SIGPIPE + println!("{}", path.display()); + true + } else { + eyre::bail!("no ghjkdir found."); + } + } + PrintCommands::GhjkfilePath => { + if let Some(path) = &cli_config.ghjkdir_path { + 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) { + let mut clap_cmd = cmd.clap; + 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 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); + 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)) +} diff --git a/src/ghjk/ext.rs b/src/ghjk/ext.rs index c515700..da8a612 100644 --- a/src/ghjk/ext.rs +++ b/src/ghjk/ext.rs @@ -42,11 +42,11 @@ impl ExtConfig { } fn inject(self, state: &mut deno_core::OpState) { + let callbacks = callbacks::worker(&self); let ctx = ExtContext { config: self, - callbacks: default(), + callbacks, }; - callbacks::worker(ctx.clone()); state.put(ctx); } } @@ -74,7 +74,7 @@ fn customizer(ext: &mut deno_core::Extension) { #[derive(Clone)] struct ExtContext { - callbacks: callbacks::Callbacks, + callbacks: Option, config: ExtConfig, } diff --git a/src/ghjk/ext/callbacks.rs b/src/ghjk/ext/callbacks.rs index 2f63aa3..6939b64 100644 --- a/src/ghjk/ext/callbacks.rs +++ b/src/ghjk/ext/callbacks.rs @@ -9,6 +9,7 @@ use deno_core::OpState; use deno_core as deno_core; // necessary for re-exported macros to work use tokio::sync::{mpsc, oneshot}; +use super::ExtConfig; use super::ExtContext; #[derive(Debug, thiserror::Error)] @@ -45,13 +46,14 @@ impl CallbackLine { fn take(&mut self) -> Option> { if !self.was_set { - warn!("callback line was not set"); + debug!("callback line was not set, worker callbacks will noop"); return None; } match self.line.take() { Some(val) => Some(val), None => { - panic!("extensions were injected twice") + debug!("realm with callbacks just had a child, it won't inherit callback feature"); + None } } } @@ -104,48 +106,42 @@ pub struct Callbacks { /// /// Stored callbacks are not Sync so this expects to be started /// on the same thread as deno. -pub fn worker(ctx: ExtContext) { - let mut line = { - let mut line = ctx.config.callbacks_rx.lock().expect_or_log("mutex err"); - let Some(line) = line.take() else { - return; - }; - line - }; - assert_eq!( - std::thread::current().name(), - Some(denort::WORKER_THREAD_NAME), - "callback worker must be launched on deno worker started with a LocalSet" - ); - // assumes local set - tokio::task::spawn_local( +pub fn worker(config: &ExtConfig) -> Option { + let mut line = config.callbacks_rx.lock().expect_or_log("mutex err"); + let mut line = line.take()?; + + let callbacks = Callbacks::default(); + let callbacks_2go = callbacks.clone(); + deno_core::unsync::spawn( async move { - debug!("callback worker starting"); + trace!("callback worker starting"); while let Some(msg) = line.recv().await { - debug!(?msg, "callback worker msg"); + trace!(?msg, "callback worker msg"); match msg { CallbacksMsg::Exec { key: name, args, response_channel, } => response_channel - .send(ctx.exec_callback(name, args).await) + .send(callbacks_2go.exec_callback(name, args).await) .expect_or_log("channel error"), } } - debug!("callback worker done"); + trace!("callback worker done"); } - .instrument(tracing::debug_span!("callback-worker")), + .instrument(tracing::trace_span!("callback-worker")), ); + Some(callbacks) } -impl ExtContext { +impl Callbacks { + #[tracing::instrument(skip(self, args))] pub async fn exec_callback( &self, key: CHeapStr, args: serde_json::Value, ) -> Result { - let Some(cb) = self.callbacks.store.get(&key[..]).map(|cb| cb.clone()) else { + let Some(cb) = self.store.get(&key[..]).map(|cb| cb.clone()) else { return Err(CallbackError::NotFound { key: key.to_string(), }); @@ -231,7 +227,7 @@ impl ExtContext { let res = match join_handle.await.expect_or_log("tokio error")? { Some(res) => res, None => { - debug!("waiting for callback proimse"); + trace!("waiting for callback proimse"); rx.await.expect_or_log("channel error")? } }; @@ -269,6 +265,7 @@ unsafe impl Send for SendPtr {} } } */ +#[tracing::instrument(skip(state, cb))] #[deno_core::op2] pub fn op_callbacks_set( state: Rc>, @@ -282,7 +279,11 @@ pub fn op_callbacks_set( (ctx.clone(), sender.clone()) }; - ctx.callbacks.store.insert( + let Some(callbacks) = ctx.callbacks else { + warn!("callback set but callback feature is not enabled"); + anyhow::bail!("callbacks feature is not enabled"); + }; + callbacks.store.insert( name.into(), Callback { js_fn: SendPtr(cb.into_raw()), diff --git a/src/ghjk/host.rs b/src/ghjk/host.rs index 4ded93f..73776c5 100644 --- a/src/ghjk/host.rs +++ b/src/ghjk/host.rs @@ -4,7 +4,8 @@ use crate::systems::*; mod deno; mod hashfile; -use hashfile::*; + +use hashfile::HashObj; #[derive(Debug)] pub struct Config { @@ -26,7 +27,7 @@ pub struct HostCtx { pub config: Config, #[educe(Debug(ignore))] pub systems: HashMap, - pub file_hash_memo: DHashMap, + pub file_hash_memo: DHashMap, } impl HostCtx { @@ -75,7 +76,12 @@ pub async fn systems_from_ghjkfile(hcx: Arc) -> Res) -> Res) -> Res, pub config: Arc, hash_obj: HashObj, - sys_instances: IndexMap, + pub sys_instances: IndexMap, old_lock_obj: Option, lockfile_path: PathBuf, hashfile_path: PathBuf, @@ -211,6 +219,12 @@ pub struct GhjkfileSystems { } 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 { @@ -235,7 +249,7 @@ impl GhjkfileSystems { if self.hcx.config.locked { warn!("locked flag set, changes to lockfile discarded"); } else { - debug!(lockfile_path = ?self.lockfile_path, ?lock_obj, "writing lock.json"); + 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"), @@ -252,7 +266,7 @@ impl GhjkfileSystems { if self.hcx.config.locked { unreachable!("code should have early exited"); } - debug!(hashfile_path = ?self.hashfile_path, hash_obj= ?self.hash_obj, "writing hash.json"); + 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) @@ -273,32 +287,11 @@ async fn serialize_ghjkfile(hcx: &HostCtx, path: &Path) -> Res<(Arc 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()), + ), + ghjkfile_hash: file_digest_hash(hcx, ghjkfile_path) + .await? + .expect_or_log("ghjkfile is gone"), + listed_files: res + .listed_file_paths + .iter() + .map(|path| pathdiff::diff_paths(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 @@ -66,7 +97,7 @@ impl HashObj { } } -pub fn env_var_digests<'a>( +fn env_var_digests<'a>( all: &IndexMap, accessed: impl Iterator, ) -> IndexMap> { @@ -80,7 +111,7 @@ pub fn env_var_digests<'a>( .collect() } -pub async fn file_digests( +async fn file_digests( hcx: &HostCtx, read_files: Vec<&Path>, ) -> Res>> { @@ -97,14 +128,19 @@ pub async fn file_digests( Ok(out.into_iter().collect()) } -pub async fn file_digest_hash(hcx: &HostCtx, path: &Path) -> Res> { +async fn file_digest_hash(hcx: &HostCtx, path: &Path) -> Res> { let path = tokio::fs::canonicalize(path) .await .wrap_err("error resolving realpath")?; match tokio::fs::metadata(&path).await { Ok(stat) => { let content_hash = if stat.file_type().is_file() || stat.file_type().is_symlink() { - Some(file_content_digest_hash(hcx, &path).await?) + Some( + file_content_digest_hash(hcx, &path) + .await? + .await + .map_err(|err| ferr!(err))?, + ) } else { None }; @@ -119,7 +155,13 @@ pub async fn file_digest_hash(hcx: &HostCtx, path: &Path) -> Res> } } -pub async fn file_content_digest_hash(hcx: &HostCtx, path: &Path) -> Res { +pub type SharedFileContentDigestFuture = + futures::future::Shared>>; + +pub async fn file_content_digest_hash( + hcx: &HostCtx, + path: &Path, +) -> Res { let path = tokio::fs::canonicalize(path) .await .wrap_err("error resolving realpath")?; @@ -127,13 +169,24 @@ pub async fn file_content_digest_hash(hcx: &HostCtx, path: &Path) -> Res Ok(occupied_entry.get().clone()), Entry::Vacant(vacant_entry) => { - // FIXME: optimize by stream hashing, this reads whole file into memory - let file = tokio::fs::read(path) - .await - .wrap_err("error reading file for")?; - let hash: CHeapStr = crate::utils::encode_base32_multibase(file).into(); - vacant_entry.insert(hash.clone()); - Ok(hash) + 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) } } } diff --git a/src/ghjk/js/00_runtime.js b/src/ghjk/js/00_runtime.js index 70e342e..89498fa 100644 --- a/src/ghjk/js/00_runtime.js +++ b/src/ghjk/js/00_runtime.js @@ -26,7 +26,7 @@ const op_callbacks_set = getOp("op_callbacks_set"); /** * @type {import('./runtime.d.ts').GhjkNs} */ -const Ghjk = { +const ____GhjkHost = { blackboard: { get: getOp("op_blackboard_get"), set: getOp("op_blackboard_set"), @@ -40,4 +40,4 @@ const Ghjk = { hostcall: getOp("op_hostcall"), }; -globalThis.Ghjk = Ghjk; +globalThis.____GhjkHost = ____GhjkHost; diff --git a/src/ghjk/js/runtime.js b/src/ghjk/js/runtime.js index c7d977e..b03bd45 100644 --- a/src/ghjk/js/runtime.js +++ b/src/ghjk/js/runtime.js @@ -4,6 +4,11 @@ // - ./00_runtime.js: which is preloaded by the custom deno runtime // - ./runtime.d.ts: which types the objects from the preload // -// The preload directly adds the Meta object the global scope but we can hide -// that implementation detail and users will "import" `Meta` from this file instead. +// The preload directly adds the Ghjk object the global scope but we can hide +// that implementation detail and users will "import" `Ghjk` from this file instead. // Or at least that is what will appear to be happening to in the type system. + +/** + * @type {import('./runtime.d.ts').GhjkNs} + */ +export const Ghjk = globalThis.____GhjkHost; diff --git a/src/ghjk/log.rs b/src/ghjk/log.rs index 76ade7e..130b02f 100644 --- a/src/ghjk/log.rs +++ b/src/ghjk/log.rs @@ -25,9 +25,9 @@ Platform: {platform} Version: {version} Args: {args:?} "#, - platform = crate::build::BUILD_TARGET, + platform = crate::shadow::BUILD_TARGET, // TODO: include commit sha - version = crate::build::PKG_VERSION, + version = crate::shadow::PKG_VERSION, args = std::env::args().collect::>() )); @@ -52,13 +52,13 @@ Args: {args:?} // std::process::exit(1); })); - // FIXME: for some reason, the tests already have - // an eyre_hook - #[cfg(not(test))] + // // FIXME: for some reason, the tests already have + // // an eyre_hook + // #[cfg(not(test))] _eyre_hook.install().unwrap(); if std::env::var("RUST_LOG").is_err() { - std::env::set_var("RUST_LOG", "info,actix_server=warn"); + std::env::set_var("RUST_LOG", "info"); } #[cfg(not(debug_assertions))] if std::env::var("RUST_SPANTRACE").is_err() { diff --git a/src/ghjk/main.rs b/src/ghjk/main.rs index 7427988..aa3714e 100644 --- a/src/ghjk/main.rs +++ b/src/ghjk/main.rs @@ -31,7 +31,7 @@ mod interlude { mod host; -mod cli {} +mod cli; mod ext; mod log; mod systems; @@ -49,144 +49,17 @@ fn main() -> Res<()> { log::init(); denort::init(); + debug!(version = shadow::PKG_VERSION, "ghjk CLI"); + tokio::runtime::Builder::new_current_thread() .enable_all() .build()? - .block_on(cli())?; + .block_on(cli::cli())?; Ok(()) } use shadow_rs::shadow; -shadow!(build); - -const DENO_UNSTABLE_FLAGS: &[&str] = &["worker-options", "kv"]; - -async fn cli() -> Res<()> { - debug!(version = build::PKG_VERSION, "ghjk CLI"); - - let cwd = std::env::current_dir()?; - - let config = { - let ghjk_dir_path = match std::env::var("GHJK_DIR") { - Ok(path) => Some(PathBuf::from(path)), - Err(std::env::VarError::NotUnicode(os_str)) => Some(PathBuf::from(os_str)), - Err(std::env::VarError::NotPresent) => { - utils::find_entry_recursive(&cwd, ".ghjk").await? - } - }; - - let ghjk_dir_path = if let Some(path) = ghjk_dir_path { - Some(tokio::fs::canonicalize(path).await?) - } else { - None - }; - - let ghjkfile_path = match &ghjk_dir_path { - Some(ghjkfile_path) => { - utils::find_entry_recursive( - ghjkfile_path - .parent() - .expect_or_log("invalid GHJK_DIR path"), - "ghjk.ts", - ) - .await? - } - None => utils::find_entry_recursive(&cwd, "ghjk.ts").await?, - }; - - let ghjkfile_path = if let Some(path) = ghjkfile_path { - Some(tokio::fs::canonicalize(path).await?) - } else { - None - }; - - if ghjk_dir_path.is_none() && ghjkfile_path.is_none() { - warn!( - "ghjk could not find any ghjkfiles or ghjkdirs, try creating a `ghjk.ts` script.", - ); - } - - let share_dir_path = match std::env::var("GHJK_SHARE_DIR") { - Ok(path) => PathBuf::from(path), - Err(std::env::VarError::NotUnicode(os_str)) => PathBuf::from(os_str), - Err(std::env::VarError::NotPresent) => directories::BaseDirs::new() - .expect_or_log("unable to resolve home dir") - .data_local_dir() - .join("ghjk"), - }; - Config { - ghjkfile_path, - ghjk_dir_path, - share_dir_path, - } - }; - - let deno_cx = denort::worker( - denort::deno::args::Flags { - unstable_config: denort::deno::args::UnstableConfig { - features: DENO_UNSTABLE_FLAGS - .iter() - .copied() - .map(String::from) - .collect(), - ..default() - }, - ..default() - }, - Some(Arc::new(Vec::new)), - ) - .await?; - - if let Some(ghjk_dir_path) = config.ghjk_dir_path { - let gcx = GhjkCtx { - ghjk_dir_path, - ghjkfile_path: config.ghjkfile_path, - share_dir_path: config.share_dir_path, - repo_root: url::Url::from_file_path(&cwd) - .expect_or_log("cwd error") - // repo root url must end in slash due to - // how Url::join works - .join(&format!("{}/", cwd.file_name().unwrap().to_string_lossy())) - .wrap_err("repo url error")?, - deno: deno_cx.clone(), - }; - let gcx = Arc::new(gcx); - - let systems_deno = systems::deno::systems_from_deno( - &gcx, - &gcx.repo_root - .join("src/deno_systems/mod.ts") - .wrap_err("repo url error")?, - ) - .await?; - - let hcx = host::HostCtx::new( - gcx, - host::Config { - re_resolve: false, - locked: false, - re_serialize: false, - env_vars: std::env::vars().collect(), - cwd, - }, - systems_deno, - ); - - let hcx = Arc::new(hcx); - - if let Some(mut systems) = host::systems_from_ghjkfile(hcx).await? { - let conf_json = serde_json::to_string_pretty(&systems.config)?; - info!(%conf_json); - systems.write_lockfile().await?; - } else { - warn!("no ghjkfile found"); - } - } - - // tokio::task::spawn_blocking(|| deno_cx.terminate()); - - Ok(()) -} +shadow!(shadow); #[derive(Debug)] pub struct GhjkCtx { @@ -200,16 +73,6 @@ pub struct GhjkCtx { #[derive(Debug)] struct Config { ghjkfile_path: Option, - ghjk_dir_path: Option, + ghjkdir_path: Option, share_dir_path: PathBuf, } - -/* mod files { - mod deno {} -} - -mod modules { - mod envs {} - mod ports {} - mod tasks {} -} */ diff --git a/src/ghjk/systems.rs b/src/ghjk/systems.rs index 0795e70..62259dd 100644 --- a/src/ghjk/systems.rs +++ b/src/ghjk/systems.rs @@ -33,6 +33,8 @@ pub trait SystemInstance { 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; @@ -44,6 +46,7 @@ pub struct ErasedSystemInstance { load_config_fn: Box< dyn Fn(serde_json::Value, ConfigBlackboard, Option) -> BoxFuture<'static, Res<()>>, >, + commands_fn: Box BoxFuture<'static, Res>>>, } impl ErasedSystemInstance { @@ -71,15 +74,25 @@ impl ErasedSystemInstance { async move { instance.gen_lock_entry().await }.boxed() }) }, - load_config_fn: Box::new(move |config, bb, state| { + load_config_fn: { 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() - }), + 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() + }) + }, } } @@ -99,6 +112,10 @@ impl ErasedSystemInstance { 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; @@ -109,4 +126,14 @@ pub struct SystemConfig { 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, +} + pub type ConfigBlackboard = Arc>; diff --git a/src/ghjk/systems/deno.rs b/src/ghjk/systems/deno.rs index 15ef2e3..a38f0d2 100644 --- a/src/ghjk/systems/deno.rs +++ b/src/ghjk/systems/deno.rs @@ -3,13 +3,15 @@ use crate::interlude::*; -use super::{SystemId, SystemInstance, SystemManifest}; +use super::{SystemCliCommand, SystemId, SystemInstance, SystemManifest}; + +mod cli; #[derive(Clone)] pub struct DenoSystemsContext { callbacks: crate::ext::CallbacksHandle, exit_code_channel: Arc>>>, - term_signal: Arc, + term_signal: tokio::sync::watch::Sender, #[allow(unused)] hostcalls: crate::ext::Hostcalls, } @@ -24,8 +26,7 @@ impl DenoSystemsContext { let Some(channel) = channel else { eyre::bail!("already terminated") }; - self.term_signal - .store(true, std::sync::atomic::Ordering::Relaxed); + self.term_signal.send(true).expect_or_log("channel error"); Ok(channel.await.expect_or_log("channel error")) } } @@ -124,8 +125,6 @@ pub async fn systems_from_deno( if exit_code != 0 { // TODO: exit signals error!(%exit_code, "deno systems died with non-zero exit code"); - } else { - info!(%exit_code, "deno systems exit") } exit_code }); @@ -137,7 +136,6 @@ pub async fn systems_from_deno( term_signal, exit_code_channel, }; - let scx = Arc::new(scx); let manifests = manifests_rx.recv().await.expect_or_log("channel error"); let manifests: Vec = @@ -169,12 +167,13 @@ struct ManifestDesc { pub struct DenoSystemManifest { desc: ManifestDesc, #[educe(Debug(ignore))] - scx: Arc, + scx: DenoSystemsContext, } impl DenoSystemManifest { + #[tracing::instrument] pub async fn ctor(&self) -> Res { - debug!(id = %self.desc.id, "initializing deno system"); + trace!("initializing deno system"); let desc = self .scx .callbacks @@ -183,7 +182,7 @@ impl DenoSystemManifest { let desc = serde_json::from_value(desc).wrap_err("protocol error")?; - debug!(id = %self.desc.id, "deno system initialized"); + trace!("deno system initialized"); Ok(DenoSystemInstance { desc, @@ -198,11 +197,12 @@ 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: Arc, + scx: DenoSystemsContext, } #[async_trait::async_trait] @@ -253,4 +253,23 @@ impl SystemInstance for DenoSystemInstance { .await .wrap_err("callback error") } + + async fn commands(&self) -> Res> { + let cmds = self + .scx + .callbacks + .exec(self.desc.cli_commands_cb_key.clone(), serde_json::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.into_clap(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 0000000..3aad4a2 --- /dev/null +++ b/src/ghjk/systems/deno/cli.rs @@ -0,0 +1,321 @@ +use crate::{interlude::*, systems::CliCommandAction}; + +#[derive(Debug, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct CliCommandDesc { + pub name: String, + + pub hide: Option, + + pub short_flag: Option, + pub 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 action_cb_key: Option, +} + +impl CliCommandDesc { + #[tracing::instrument(skip(scx))] + pub fn into_clap(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.short_flag { + cmd = cmd.short_flag(val) + } + if let Some(val) = self.aliases { + cmd = cmd.aliases(val) + } + if let Some(val) = &self.about { + cmd = cmd.about(val) + } + if let Some(val) = self.before_help { + cmd = cmd.before_long_help(val) + } + if let Some(val) = self.before_long_help { + cmd = cmd.before_long_help(val) + } + + if let Some(val) = self.args { + for (id, desc) in val { + let arg = desc.into_clap(id); + cmd = cmd.arg(arg); + } + } + 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.into_clap(id); + cmd = cmd.arg(arg); + } + ids + } else { + default() + }; + 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.into_clap(scx.clone()); + // cmd = cmd.subcommand(scmd.clap.take().unwrap()); + subcommands.insert(id.into(), scmd); + } + subcommands + } else { + default() + }; + + let action: Option = if let Some(val) = self.action_cb_key { + let flag_ids = Arc::new(flag_ids); + let cb_key = CHeapStr::from(val); + Some(Box::new(move |matches| { + let scx = scx.clone(); + let flag_ids = flag_ids.clone(); + let cb_key = cb_key.clone(); + deno_cb_action(matches, scx.clone(), cb_key, flag_ids).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_ids: 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(value) = matches + .try_remove_occurrences::(id.as_str()) + .wrap_err_with(|| format!("error extracting match occurunce for {id}"))? + else { + continue; + }; + let value: Vec> = value.map(Iterator::collect).collect(); + let value = if value.len() == 1 && value[0].len() < 2 { + serde_json::json!(value.first()) + } else if value.len() == 1 { + serde_json::json!(value[0]) + } else { + serde_json::json!(value) + }; + + let bucket = if flag_ids.contains(id.as_str()) { + &mut flags + } else { + &mut args + }; + + bucket.insert(id.as_str().to_owned(), value); + } + scx.callbacks + .exec( + cb_key.clone(), + serde_json::json!({ + "flags": flags, + "args": args + }), + ) + .await + .wrap_err("callback error")?; + Ok(()) +} + +#[derive(Debug, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct CliArgDesc { + pub required: Option, + pub global: Option, + pub hide: Option, + pub exclusive: 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 into_clap(self, id: String) -> clap::Arg { + let mut arg = clap::Arg::new(id); + + 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.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) + }; + if let Some(val) = self.visible_short_aliases { + arg = arg.short_aliases(val) + }; + + 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 into_clap(self, id: String) -> clap::Arg { + let mut arg = self.arg.into_clap(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) + }; + if let Some(val) = self.visible_short_aliases { + arg = arg.short_aliases(val) + }; + + arg + } +} + +#[derive(Deserialize, Debug)] +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::Unknown, + AnyPath => clap::ValueHint::Unknown, + FilePath => clap::ValueHint::Unknown, + DirPath => clap::ValueHint::Unknown, + ExecutablePath => clap::ValueHint::Unknown, + CommandName => clap::ValueHint::Unknown, + CommandString => clap::ValueHint::Unknown, + CommandWithArguments => clap::ValueHint::Unknown, + Username => clap::ValueHint::Unknown, + Hostname => clap::ValueHint::Unknown, + Url => clap::ValueHint::Unknown, + EmailAddress => clap::ValueHint::Unknown, + } + } +} diff --git a/src/ghjk/utils.rs b/src/ghjk/utils.rs index 30e1201..3d7583c 100644 --- a/src/ghjk/utils.rs +++ b/src/ghjk/utils.rs @@ -144,10 +144,13 @@ pub fn hash_obj(obj: &T) -> String { } 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(string.as_bytes()) - .expect_or_log("error writing to hasher"); + hash.write(bytes).expect_or_log("error writing to hasher"); let hash = hash.finalize(); let hash = @@ -155,6 +158,35 @@ pub fn hash_str(string: &str) -> String { 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; 4096]; + + 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{}", diff --git a/src/play/Cargo.toml b/src/play/Cargo.toml new file mode 100644 index 0000000..f12e33a --- /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 0000000..6994e43 --- /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/main.rs b/src/xtask/main.rs index 5baa34f..803fe49 100644 --- a/src/xtask/main.rs +++ b/src/xtask/main.rs @@ -49,6 +49,15 @@ fn main() -> Res<()> { 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(()) } From ac4a991ab0411b4542d821dfc9f183e7ea7d2418 Mon Sep 17 00:00:00 2001 From: Yohe-Am <56622350+Yohe-Am@users.noreply.github.com> Date: Wed, 4 Dec 2024 05:42:47 +0300 Subject: [PATCH 02/13] fix: clap issues --- Cargo.lock | 1 + Cargo.toml | 2 + modules/envs/mod.ts | 197 +++------------------ modules/ports/mod.ts | 325 ++++++++++++++++++----------------- modules/tasks/mod.ts | 84 +++++---- src/deno_systems/types.ts | 26 ++- src/denort/lib.rs | 4 +- src/ghjk/Cargo.toml | 17 +- src/ghjk/cli.rs | 42 ++++- src/ghjk/main.rs | 5 +- src/ghjk/systems.rs | 10 ++ src/ghjk/systems/deno.rs | 52 ++++-- src/ghjk/systems/deno/cli.rs | 56 +++++- src/xtask/main.rs | 34 ++-- utils/mod.ts | 2 +- 15 files changed, 428 insertions(+), 429 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 20c5d2f..8531f6f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3423,6 +3423,7 @@ dependencies = [ "async-trait", "bitflags 2.6.0", "clap", + "clap_complete", "color-eyre", "dashmap", "data-encoding", diff --git a/Cargo.toml b/Cargo.toml index 2372000..91f09b0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,8 @@ once_cell = "1" # version must match on clap in `deno` clap = "=4.5" +clap_complete = "=4.5.24" + shadow-rs = "0.36.0" diff --git a/modules/envs/mod.ts b/modules/envs/mod.ts index fd24b0e..1568484 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 { @@ -90,9 +90,11 @@ export class EnvsModule extends ModuleBase { : { envKey: envKeyMaybe ?? ecx.activeEnv }; } - const commonFlags = { + const commonFlags: CliCommand["flags"] = { taskEnv: { - value_name: "taskName", + short: "t", + long: "task-env", + value_name: "TASK NAME", help: "Activate the environment used by the named task", exclusive: true, }, @@ -100,14 +102,14 @@ export class EnvsModule extends ModuleBase { const commonArgs = { envKey: { - value_name: "envKey", + value_name: "ENV KEY", }, }; return [ { name: "envs", - aliases: ["e"], + visible_aliases: ["e"], about: "Envs module, reproducable posix shells environments.", sub_commands: [ { @@ -140,11 +142,14 @@ export class EnvsModule extends ModuleBase { ...commonArgs, }, action: async function ( - { flags: { taskEnv }, args: { envName: envKeyMaybe } }, + { + flags: { taskEnv: taskKeyMaybe }, + args: { envName: envKeyMaybe }, + }, ) { const { envKey } = envKeyArgs({ - taskKeyMaybe: taskEnv, - envKeyMaybe, + taskKeyMaybe: taskKeyMaybe as string, + envKeyMaybe: envKeyMaybe as string, }); await activateEnv(envKey); }, @@ -161,11 +166,14 @@ export class EnvsModule extends ModuleBase { ...commonArgs, }, action: async function ( - { flags: { taskEnv }, args: { envName: envKeyMaybe } }, + { + flags: { taskEnv: taskKeyMaybe }, + args: { envName: envKeyMaybe }, + }, ) { const { envKey, envName } = envKeyArgs({ - taskKeyMaybe: taskEnv, - envKeyMaybe, + taskKeyMaybe: taskKeyMaybe as string, + envKeyMaybe: envKeyMaybe as string, }); await reduceAndCookEnv(gcx, ecx, envKey, envName ?? envKey); }, @@ -184,11 +192,14 @@ export class EnvsModule extends ModuleBase { ...commonArgs, }, action: async function ( - { flags: { taskEnv }, args: { envName: envKeyMaybe } }, + { + flags: { taskEnv: taskKeyMaybe }, + args: { envName: envKeyMaybe }, + }, ) { const { envKey } = envKeyArgs({ - taskKeyMaybe: taskEnv, - envKeyMaybe, + taskKeyMaybe: taskKeyMaybe as string, + envKeyMaybe: envKeyMaybe as string, }); const env = ecx.config.envs[envKey]; if (!env) { @@ -213,11 +224,11 @@ export class EnvsModule extends ModuleBase { ...commonArgs, }, action: async function ( - { flags: { taskEnv }, args: { envName: envKeyMaybe } }, + { flags: { taskEnv: taskKeyMaybe }, args: { envName: envKeyMaybe } }, ) { const { envKey, envName } = envKeyArgs({ - taskKeyMaybe: taskEnv, - envKeyMaybe, + taskKeyMaybe: taskKeyMaybe as string, + envKeyMaybe: envKeyMaybe as string, }); await reduceAndCookEnv( gcx, @@ -230,158 +241,6 @@ export class EnvsModule extends ModuleBase { }, ]; } - commands2() { - const gcx = this.gcx; - const ecx = getEnvsCtx(this.gcx); - - function envKeyArgs( - args: { - taskKeyMaybe?: string; - envKeyMaybe?: string; - }, - ) { - const { envKeyMaybe, taskKeyMaybe } = args; - if (taskKeyMaybe && envKeyMaybe) { - throw new Error( - "--task-env option can not be combined with [envName] argument", - ); - } - if (taskKeyMaybe) { - const tasksCx = getTasksCtx(gcx); - const taskDef = tasksCx.config.tasks[taskKeyMaybe]; - if (!taskDef) { - throw new Error(`no task found under key "${taskKeyMaybe}"`); - } - return { envKey: taskDef.envKey }; - } - const actualKey = ecx.config.envsNamed[envKeyMaybe ?? ecx.activeEnv]; - return actualKey - ? { envKey: actualKey, envName: envKeyMaybe ?? ecx.activeEnv } - : { 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(() => { - // deno-lint-ignore no-console - console.log( - Object.entries(ecx.config.envsNamed) - // envs that have names which start with underscors - // don't show up in the cli list - .filter(([key]) => !key.startsWith("_")) - .map(([name, hash]) => { - const { desc } = ecx.config.envs[hash]; - return `${name}${desc ? ": " + desc : ""}`; - }) - .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) { - const { envKey } = envKeyArgs({ - taskKeyMaybe: taskEnv, - envKeyMaybe, - }); - 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) { - const { envKey, envName } = envKeyArgs({ - taskKeyMaybe: taskEnv, - envKeyMaybe, - }); - await reduceAndCookEnv(gcx, ecx, envKey, envName ?? envKey); - }), - ) - .command( - "show", - new cliffy_cmd.Command() - .description(`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) { - const { envKey } = envKeyArgs({ - taskKeyMaybe: taskEnv, - envKeyMaybe, - }); - const env = ecx.config.envs[envKey]; - if (!env) { - 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) { - const { envKey, envName } = envKeyArgs({ - taskKeyMaybe: taskEnv, - envKeyMaybe, - }); - await reduceAndCookEnv( - gcx, - ecx, - envKey, - envName ?? envKey, - ); - await activateEnv(envKey); - }), - }; - } loadLockEntry(raw: Json) { const entry = lockValidator.parse(raw); diff --git a/modules/ports/mod.ts b/modules/ports/mod.ts index 811d09e..4221e65 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; @@ -111,166 +112,60 @@ export class PortsModule extends ModuleBase { } override commands() { - return []; - } - - commands2() { const gcx = this.gcx; const pcx = getPortsCtx(gcx); - 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"); - }), - ), - }; + 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 string | undefined, + ); + }, + }, + ], + }]; + return out; } + loadLockEntry(raw: Json) { const entry = lockValidator.parse(raw); @@ -304,6 +199,122 @@ export class PortsModule extends ModuleBase { } } +async function outdatedCommand( + gcx: GhjkCtx, + pcx: PortsCtx, + updateInstallFlag?: string, + updateAllFlag?: string, +) { + 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 installName = updateInstallFlag; + // 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 (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/tasks/mod.ts b/modules/tasks/mod.ts index 62ac0c1..a7846ec 100644 --- a/modules/tasks/mod.ts +++ b/modules/tasks/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 { Json, unwrapZodRes } from "../../utils/mod.ts"; import validators from "./types.ts"; @@ -11,6 +11,7 @@ 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; @@ -47,54 +48,47 @@ export class TasksModule extends ModuleBase { } override commands() { - return []; - } - - commands2() { 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. - -The named tasks in your ghjkfile will be listed here.`); - 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.", + 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: async ({ args: { raw } }) => { + await execTask( + gcx, + tcx.config, + tcx.taskGraph, + key, + (raw as string[]) ?? [], + ); + }, + } as CliCommand; + }, + ), + ], + }]; + return out; } loadLockEntry(raw: Json) { diff --git a/src/deno_systems/types.ts b/src/deno_systems/types.ts index 6e8b1f3..2cc7273 100644 --- a/src/deno_systems/types.ts +++ b/src/deno_systems/types.ts @@ -26,10 +26,23 @@ const cliArg = zod.object({ "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(), @@ -50,7 +63,6 @@ const cliFlag = cliArg.extend({ const cliCommandBase = zod.object({ name: zod.string(), - short_flag: charSchema.optional(), aliases: zod.string().array().optional(), visible_aliases: zod.string().array().optional(), @@ -64,9 +76,17 @@ const cliCommandBase = zod.object({ flags: zod.record(cliFlag).optional().optional(), }); +const flagsAndArgs = zod.record( + zod.union([ + zod.string(), + zod.string().array(), + zod.string().array().array(), + ]).optional(), +); + const cliActionArgs = zod.object({ - flags: zod.record(zod.string().optional()), - args: zod.record(zod.string().optional()), + flags: flagsAndArgs, + args: flagsAndArgs, }); const cliCommandActionBase = cliCommandBase.extend({ diff --git a/src/denort/lib.rs b/src/denort/lib.rs index b84d8f7..bfacbb7 100644 --- a/src/denort/lib.rs +++ b/src/denort/lib.rs @@ -89,7 +89,7 @@ pub async fn worker( } } } - std::mem::forget(cx); + // std::mem::forget(cx); trace!("deno worker done"); } .instrument(tracing::trace_span!("deno-worker")), @@ -159,7 +159,7 @@ async fn module_worker( .expect_or_log("channel error"), } } - std::mem::forget(module_cx); + // std::mem::forget(module_cx); trace!("module worker done"); } .instrument(tracing::trace_span!( diff --git a/src/ghjk/Cargo.toml b/src/ghjk/Cargo.toml index 5335c17..605a9ea 100644 --- a/src/ghjk/Cargo.toml +++ b/src/ghjk/Cargo.toml @@ -1,5 +1,6 @@ [package] name = "ghjk" +description = "Programmable runtime manager." version.workspace = true edition.workspace = true @@ -13,12 +14,17 @@ 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 = "*" bitflags = "*" @@ -46,24 +52,25 @@ tracing-subscriber.workspace = true tracing-appender = "0.2" tracing-futures = "0.2" +async-trait = "0.1.83" +futures-concurrency = "7.6.2" +futures = { version = "=0.3.30", default-features = false, features = ["std", "async-await"] } tokio = { workspace = true, features = ["full", "parking_lot"] } 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 -nix = { version = "0.29.0", features = ["signal"] } -indexmap = { version = "2.6.0", features = ["serde"] } -futures-concurrency = "7.6.2" -futures = { version = "=0.3.30", default-features = false, features = ["std", "async-await"] } + 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" -async-trait = "0.1.83" [build-dependencies] shadow-rs.workspace = true diff --git a/src/ghjk/cli.rs b/src/ghjk/cli.rs index 88bdd51..83fcdc6 100644 --- a/src/ghjk/cli.rs +++ b/src/ghjk/cli.rs @@ -1,3 +1,7 @@ +use std::process::ExitCode; + +use clap::builder::styling::AnsiColor; + use crate::interlude::*; use crate::systems::{CliCommandAction, SystemCliCommand}; @@ -5,7 +9,7 @@ use crate::{host, systems, utils, Config}; const DENO_UNSTABLE_FLAGS: &[&str] = &["worker-options", "kv"]; -pub async fn cli() -> Res<()> { +pub async fn cli() -> Res { let cwd = std::env::current_dir()?; let config = { @@ -64,7 +68,7 @@ pub async fn cli() -> Res<()> { }; let Some(quick_err) = try_quick_cli(&config).await? else { - return Ok(()); + return Ok(ExitCode::SUCCESS); }; let Some(ghjk_dir_path) = config.ghjkdir_path.clone() else { @@ -146,7 +150,9 @@ pub async fn cli() -> Res<()> { }; for cmd in sys_cmds { - root_cmd = root_cmd.subcommand(cmd); + // apply styles again here due to propagation + // breaking for these dynamic subcommands for some reason + root_cmd = root_cmd.subcommand(cmd.styles(CLAP_STYLE)); } let matches = match root_cmd.try_get_matches() { @@ -160,7 +166,7 @@ pub async fn cli() -> Res<()> { match QuickComands::from_arg_matches(&matches) { Ok(QuickComands::Print { commands }) => { _ = commands.action(&config, Some(&systems.config))?; - return Ok(()); + return Ok(ExitCode::SUCCESS); } Err(err) => { let kind = err.kind(); @@ -186,9 +192,9 @@ pub async fn cli() -> Res<()> { }; let Some(action) = action.action else { - action.clap.print_long_help()?; systems.write_lockfile_or_log().await; - return Ok(()); + action.clap.print_long_help()?; + return Ok(std::process::ExitCode::FAILURE); }; let res = action(action_matches.clone()) @@ -199,7 +205,7 @@ pub async fn cli() -> Res<()> { deno_cx.terminate().await?; - res + res.map(|()| ExitCode::SUCCESS) } /// Sections of the CLI do not require loading a ghjkfile. @@ -235,8 +241,18 @@ pub async fn try_quick_cli(config: &Config) -> Res> { Ok(None) } -#[derive(clap::Parser, Debug)] -#[command(version, about)] +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, @@ -341,6 +357,7 @@ async fn commands_from_systems( ) } 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 @@ -349,6 +366,13 @@ async fn commands_from_systems( .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); } diff --git a/src/ghjk/main.rs b/src/ghjk/main.rs index aa3714e..0daf983 100644 --- a/src/ghjk/main.rs +++ b/src/ghjk/main.rs @@ -39,7 +39,7 @@ mod utils; use crate::interlude::*; -fn main() -> Res<()> { +fn main() -> Res { // FIXME: change signal handler for children // FIXME: use unix_sigpipe once https://github.com/rust-lang/rust/issues/97889 lands unsafe { @@ -54,8 +54,7 @@ fn main() -> Res<()> { tokio::runtime::Builder::new_current_thread() .enable_all() .build()? - .block_on(cli::cli())?; - Ok(()) + .block_on(cli::cli()) } use shadow_rs::shadow; diff --git a/src/ghjk/systems.rs b/src/ghjk/systems.rs index 62259dd..c0b34f1 100644 --- a/src/ghjk/systems.rs +++ b/src/ghjk/systems.rs @@ -136,4 +136,14 @@ pub struct SystemCliCommand { 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 index a38f0d2..63b1ba5 100644 --- a/src/ghjk/systems/deno.rs +++ b/src/ghjk/systems/deno.rs @@ -10,7 +10,7 @@ mod cli; #[derive(Clone)] pub struct DenoSystemsContext { callbacks: crate::ext::CallbacksHandle, - exit_code_channel: Arc>>>, + exit_code_channel: Arc>>>>, term_signal: tokio::sync::watch::Sender, #[allow(unused)] hostcalls: crate::ext::Hostcalls, @@ -18,7 +18,7 @@ pub struct DenoSystemsContext { impl DenoSystemsContext { #[allow(unused)] - pub async fn terminate(&mut self) -> Res { + pub async fn terminate(&mut self) -> Res<()> { let channel = { let mut opt = self.exit_code_channel.lock().expect_or_log("mutex error"); opt.take() @@ -27,7 +27,7 @@ impl DenoSystemsContext { eyre::bail!("already terminated") }; self.term_signal.send(true).expect_or_log("channel error"); - Ok(channel.await.expect_or_log("channel error")) + channel.await.expect_or_log("channel error") } } @@ -114,20 +114,41 @@ pub async fn systems_from_deno( ) .await?; worker.execute().await?; - let (exit_code_channel, term_signal, _) = worker.drive_till_exit().await?; + let (mut exit_code_channel, term_signal, _) = worker.drive_till_exit().await?; + + let manifests = tokio::select! { + res = &mut exit_code_channel => { + 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 dcx = gcx.deno.clone(); let join_exit_code_watcher = tokio::spawn(async { - let exit_code = exit_code_channel - .await - .expect_or_log("channel error") - .wrap_err("error on event loop for deno systems") - .unwrap_or_log(); - if exit_code != 0 { - // TODO: exit signals - error!(%exit_code, "deno systems died with non-zero exit code"); - } - exit_code + let err = match exit_code_channel.await.expect_or_log("channel error") { + Ok(0) => return Ok(()), + Ok(exit_code) => { + error!(%exit_code, "deno systems died with non-zero exit code"); + let err = ferr!("deno systems died with non-zero exit code: {exit_code}"); + error!("{err}"); + err + } + Err(err) => err.wrap_err("error on event loop for deno systems"), + }; + // TODO: better exit signals + debug!("killing whole deno context"); + dcx.terminate().await.unwrap(); + Err(err) }); + let exit_code_channel = Arc::new(std::sync::Mutex::new(Some(join_exit_code_watcher))); let scx = DenoSystemsContext { @@ -137,9 +158,6 @@ pub async fn systems_from_deno( exit_code_channel, }; - let manifests = manifests_rx.recv().await.expect_or_log("channel error"); - let manifests: Vec = - serde_json::from_value(manifests).wrap_err("protocol error")?; let manifests = manifests .into_iter() .map(|desc| { diff --git a/src/ghjk/systems/deno/cli.rs b/src/ghjk/systems/deno/cli.rs index 3aad4a2..057d8b8 100644 --- a/src/ghjk/systems/deno/cli.rs +++ b/src/ghjk/systems/deno/cli.rs @@ -7,8 +7,8 @@ pub struct CliCommandDesc { pub hide: Option, - pub short_flag: Option, pub aliases: Option>, + pub visible_aliases: Option>, pub about: Option, pub before_help: Option, @@ -30,17 +30,17 @@ impl CliCommandDesc { if let Some(val) = self.hide { cmd = cmd.hide(val) } - if let Some(val) = self.short_flag { - cmd = cmd.short_flag(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_long_help(val) + cmd = cmd.before_help(val) } if let Some(val) = self.before_long_help { cmd = cmd.before_long_help(val) @@ -68,7 +68,6 @@ impl CliCommandDesc { for desc in val { let id = desc.name.clone(); let scmd = desc.into_clap(scx.clone()); - // cmd = cmd.subcommand(scmd.clap.take().unwrap()); subcommands.insert(id.into(), scmd); } subcommands @@ -92,7 +91,6 @@ impl CliCommandDesc { None }; - crate::systems::SystemCliCommand { name: name.into(), clap: cmd, @@ -160,6 +158,10 @@ pub struct CliArgDesc { 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, @@ -194,6 +196,16 @@ impl CliArgDesc { 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) @@ -319,3 +331,33 @@ impl From for clap::ValueHint { } } } + +#[derive(Deserialize, Debug)] +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/xtask/main.rs b/src/xtask/main.rs index 803fe49..a1841ab 100644 --- a/src/xtask/main.rs +++ b/src/xtask/main.rs @@ -9,6 +9,8 @@ mod interlude { pub use tracing::{debug, error, info, trace, warn}; pub use tracing_unwrap::*; } +use clap::builder::styling::AnsiColor; + use crate::interlude::*; mod utils; @@ -48,22 +50,32 @@ fn main() -> Res<()> { 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), - ), */ + } /* 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)] +#[clap( + version, + about, + styles = CLAP_STYLE +)] struct Args { #[clap(subcommand)] command: Commands, diff --git a/utils/mod.ts b/utils/mod.ts index 2e77256..0082d8b 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; } From e49fef5a538d59bd417099ba0bee7e0e54a615be Mon Sep 17 00:00:00 2001 From: Yohe-Am <56622350+Yohe-Am@users.noreply.github.com> Date: Thu, 5 Dec 2024 09:26:40 +0300 Subject: [PATCH 03/13] feat: deno subcmd --- .ghjk/deno.lock | 321 ++++-------- .ghjk/lock.json | 51 +- .github/workflows/nightly.yml | 2 +- .github/workflows/tests.yml | 2 +- Cargo.lock | 930 +++++++++++++++++++++++++--------- Cargo.toml | 8 +- deno.jsonc | 2 +- deno.lock | 369 +------------- ghjk.ts | 18 +- install.sh | 2 +- install/mod.ts | 32 +- src/ghjk/Cargo.toml | 2 + src/ghjk/cli.rs | 113 ++++- src/ghjk/main.rs | 14 +- tests/test-alpine.Dockerfile | 4 +- tests/test.Dockerfile | 4 +- tests/utils.ts | 21 +- utils/mod.ts | 2 + 18 files changed, 991 insertions(+), 906 deletions(-) diff --git a/.ghjk/deno.lock b/.ghjk/deno.lock index 98d050b..670c2b7 100644 --- a/.ghjk/deno.lock +++ b/.ghjk/deno.lock @@ -1,95 +1,100 @@ { - "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" - ] + "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-validation-error@3.4.0": "npm:zod-validation-error@3.4.0_zod@3.23.8", + "npm:zod@3.23.8": "npm:zod@3.23.8" }, - "zod-validation-error@3.4.0_zod@3.23.8": { - "integrity": "sha512-ZOPR9SVY6Pb2qqO5XHt+MkkTRxGXb4EVtnjc9JpXUOtUB1T9Ru7mZOT361AN3MsetVe7R0a1KZshJDZdgp9miQ==", - "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@3.23.8": { - "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==" + "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-validation-error@3.4.0_zod@3.23.8": { + "integrity": "sha512-ZOPR9SVY6Pb2qqO5XHt+MkkTRxGXb4EVtnjc9JpXUOtUB1T9Ru7mZOT361AN3MsetVe7R0a1KZshJDZdgp9miQ==", + "dependencies": { + "zod": "zod@3.23.8" + } + }, + "zod@3.23.8": { + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "dependencies": {} + } } }, "remote": { @@ -396,145 +401,8 @@ "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", @@ -571,7 +439,6 @@ "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/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", diff --git a/.ghjk/lock.json b/.ghjk/lock.json index 0e9eb94..5da7196 100644 --- a/.ghjk/lock.json +++ b/.ghjk/lock.json @@ -269,7 +269,7 @@ "bciqe72molvtvcuj3tuh47ziue2oqd6t4qetxn3rsoa764ofup6uwjmi", "bciqe4zlekl4uqqbhxunac7br24mrf6cdpfrfblahqa4vrgaqjujcl4i", "bciqpu4klxr3hl6ujhmflrlfd3dxp47ijq26mnathb26ojzwkeggy5ii", - "bciqpy7sxlin5fqcbsl7vildckib5p65mei4qxya2fsbgvi2pqt3jimq" + "bciqelae2kzmf7umbo62flzq2mnlhnc4ilbfmn4va2fzrqwx7w7zusji" ], "allowedBuildDeps": "bciqoo3t36t4pphdox5wa5ugn34wkar7rwkqgb5l55lwnxbuabcc3nyq" }, @@ -281,7 +281,7 @@ "bciqe72molvtvcuj3tuh47ziue2oqd6t4qetxn3rsoa764ofup6uwjmi", "bciqe4zlekl4uqqbhxunac7br24mrf6cdpfrfblahqa4vrgaqjujcl4i", "bciqpu4klxr3hl6ujhmflrlfd3dxp47ijq26mnathb26ojzwkeggy5ii", - "bciqpy7sxlin5fqcbsl7vildckib5p65mei4qxya2fsbgvi2pqt3jimq" + "bciqelae2kzmf7umbo62flzq2mnlhnc4ilbfmn4va2fzrqwx7w7zusji" ], "allowedBuildDeps": "bciqoo3t36t4pphdox5wa5ugn34wkar7rwkqgb5l55lwnxbuabcc3nyq" }, @@ -294,9 +294,13 @@ "bciqe72molvtvcuj3tuh47ziue2oqd6t4qetxn3rsoa764ofup6uwjmi", "bciqe4zlekl4uqqbhxunac7br24mrf6cdpfrfblahqa4vrgaqjujcl4i", "bciqpu4klxr3hl6ujhmflrlfd3dxp47ijq26mnathb26ojzwkeggy5ii", - "bciqpy7sxlin5fqcbsl7vildckib5p65mei4qxya2fsbgvi2pqt3jimq" + "bciqelae2kzmf7umbo62flzq2mnlhnc4ilbfmn4va2fzrqwx7w7zusji" ], "allowedBuildDeps": "bciqoo3t36t4pphdox5wa5ugn34wkar7rwkqgb5l55lwnxbuabcc3nyq" + }, + "ghjkEnvProvInstSet_______task_env_cache-v8": { + "installs": [], + "allowedBuildDeps": "bciqeie3punk3gz4kcfdk2fxx5bsj5fh3j7bb7z36qmimayhwdsvp7cq" } } } @@ -308,13 +312,13 @@ "lock-sed": { "ty": "denoFile@v1", "key": "lock-sed", - "envKey": "bciqpstuhgkq5ne5uv4wobyf2houlb2leq5uvhevfmkr7rqudwro2f6i" + "envKey": "bciqcjjccn4eivzzybioty5p5tde6gnafea43rypzxci54tqjfglxyyy" }, "cache-v8": { "ty": "denoFile@v1", "key": "cache-v8", "desc": "Install the V8 builds to a local cache.", - "envKey": "bciqksijm3dibc72cqwbp7e6chayqnuhvpzj24ev6zzsjhn3bmt6copq" + "envKey": "bciqngtgh6vxbmug3jgfhtc6t2o7d4375gzfwxca2hmq2mhwbe4tajvq" } }, "tasksNamed": [ @@ -327,13 +331,21 @@ "id": "envs", "config": { "envs": { - "bciqjpw6xgc3ajnko2ymjuapnthfzgifz4yacuw62zjx4t6w2ya55mda": { + "bciqngtgh6vxbmug3jgfhtc6t2o7d4375gzfwxca2hmq2mhwbe4tajvq": { + "provides": [ + { + "ty": "ghjk.ports.InstallSetRef", + "setId": "ghjkEnvProvInstSet_______task_env_cache-v8" + } + ] + }, + "bciqkjh3l5pvnydjxc3gp6autcaurxvw2euj7uz472qureg3p4y5nfuq": { "desc": "the default default environment.", "provides": [ { "ty": "posix.envVar", "key": "RUST_LOG", - "val": "debug,deno=info,denort=trace,swc_ecma_transforms_base=info" + "val": "info,deno=info,denort=trace,swc_ecma_transforms_base=info" }, { "ty": "ghjk.ports.InstallSetRef", @@ -341,12 +353,12 @@ } ] }, - "bciqpstuhgkq5ne5uv4wobyf2houlb2leq5uvhevfmkr7rqudwro2f6i": { + "bciqcjjccn4eivzzybioty5p5tde6gnafea43rypzxci54tqjfglxyyy": { "provides": [ { "ty": "posix.envVar", "key": "RUST_LOG", - "val": "debug,deno=info,denort=trace,swc_ecma_transforms_base=info" + "val": "info,deno=info,denort=trace,swc_ecma_transforms_base=info" }, { "ty": "ghjk.ports.InstallSetRef", @@ -354,12 +366,12 @@ } ] }, - "bciqksijm3dibc72cqwbp7e6chayqnuhvpzj24ev6zzsjhn3bmt6copq": { + "bciqothoegu7lnencjdk6pjtassehqlzaldan6l67lmtd2slhmvnq5la": { "provides": [ { "ty": "posix.envVar", "key": "RUST_LOG", - "val": "debug,deno=info,denort=trace,swc_ecma_transforms_base=info" + "val": "info,deno=info,denort=trace,swc_ecma_transforms_base=info" }, { "ty": "ghjk.ports.InstallSetRef", @@ -367,12 +379,12 @@ } ] }, - "bciqh3i5r22rdn63dpluzbp7buhz5ko2jsyarp3nlet2kqzypdfpmlqi": { + "bciqdlbved4xvo27dss37motxje63ai3mwc4g5otjre5heqto2g7zbhi": { "provides": [ { "ty": "posix.envVar", "key": "RUST_LOG", - "val": "debug,deno=info,denort=trace,swc_ecma_transforms_base=info" + "val": "info,deno=info,denort=trace,swc_ecma_transforms_base=info" }, { "ty": "posix.envVar", @@ -388,9 +400,9 @@ }, "defaultEnv": "dev", "envsNamed": { - "main": "bciqjpw6xgc3ajnko2ymjuapnthfzgifz4yacuw62zjx4t6w2ya55mda", - "_rust": "bciqksijm3dibc72cqwbp7e6chayqnuhvpzj24ev6zzsjhn3bmt6copq", - "dev": "bciqh3i5r22rdn63dpluzbp7buhz5ko2jsyarp3nlet2kqzypdfpmlqi" + "main": "bciqkjh3l5pvnydjxc3gp6autcaurxvw2euj7uz472qureg3p4y5nfuq", + "_rust": "bciqothoegu7lnencjdk6pjtassehqlzaldan6l67lmtd2slhmvnq5la", + "dev": "bciqdlbved4xvo27dss37motxje63ai3mwc4g5otjre5heqto2g7zbhi" } } } @@ -480,8 +492,8 @@ }, "packageName": "vale" }, - "bciqpy7sxlin5fqcbsl7vildckib5p65mei4qxya2fsbgvi2pqt3jimq": { - "version": "2.0.6", + "bciqelae2kzmf7umbo62flzq2mnlhnc4ilbfmn4va2fzrqwx7w7zusji": { + "version": "2.1.2", "port": { "ty": "denoWorker@v1", "name": "deno_ghrel", @@ -910,7 +922,8 @@ "moduleSpecifier": "file:///ports/mold.ts" }, "replaceLd": true - } + }, + "bciqeie3punk3gz4kcfdk2fxx5bsj5fh3j7bb7z36qmimayhwdsvp7cq": {} } } } diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 2466d31..0380726 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -4,7 +4,7 @@ on: workflow_dispatch: env: - DENO_VERSION: "2.0.6" + DENO_VERSION: "2.1.2" GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GHJK_LOG_PANIC_LEVEL: error DENO_DIR: .deno-dir diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6f33085..19763f7 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -9,7 +9,7 @@ on: - ready_for_review env: - DENO_VERSION: "2.0.6" + DENO_VERSION: "2.1.2" GHJK_LOG: debug GHJK_LOG_PANIC_LEVEL: error DENO_DIR: .deno-dir diff --git a/Cargo.lock b/Cargo.lock index 8531f6f..a8c1ed4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -354,6 +354,59 @@ 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" @@ -438,25 +491,22 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.69.5" +version = "0.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" +checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" dependencies = [ "bitflags 2.6.0", "cexpr", "clang-sys", - "itertools 0.10.5", - "lazy_static", - "lazycell", + "itertools 0.13.0", "log", - "prettyplease 0.2.25", + "prettyplease", "proc-macro2", "quote", "regex", "rustc-hash", "shlex", "syn 2.0.87", - "which 4.4.2", ] [[package]] @@ -534,6 +584,16 @@ 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" @@ -836,9 +896,9 @@ checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" [[package]] name = "comrak" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c93ab3577cca16b4a1d80a88c2e0cd8b6e969e51696f0bbb0d1dcb0157109832" +checksum = "d8c32ff8b21372fab0e9ecc4e42536055702dc5faa418362bffd1544f9d12637" dependencies = [ "caseless", "derive_builder", @@ -851,6 +911,20 @@ dependencies = [ "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_static_text" version = "0.8.1" @@ -1188,8 +1262,8 @@ dependencies = [ [[package]] name = "deno" -version = "2.0.6" -source = "git+https://github.com/metatypedev/deno?branch=v2.0.6-embeddable#5bf5dcaa89967e67e5a156de02b512bf06dc3fbd" +version = "2.1.2" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" dependencies = [ "anstream", "async-trait", @@ -1220,6 +1294,7 @@ dependencies = [ "deno_runtime", "deno_semver", "deno_task_shell", + "deno_telemetry", "deno_terminal 0.2.0", "deno_tower_lsp", "dissimilar", @@ -1240,7 +1315,7 @@ dependencies = [ "http-body-util", "hyper-util", "import_map", - "indexmap", + "indexmap 2.6.0", "jsonc-parser", "junction", "lazy-regex", @@ -1276,6 +1351,7 @@ dependencies = [ "sha2", "shell-escape", "spki", + "sqlformat", "strsim", "tar", "tempfile", @@ -1354,8 +1430,8 @@ dependencies = [ [[package]] name = "deno_broadcast_channel" -version = "0.171.0" -source = "git+https://github.com/metatypedev/deno?branch=v2.0.6-embeddable#5bf5dcaa89967e67e5a156de02b512bf06dc3fbd" +version = "0.174.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" dependencies = [ "async-trait", "deno_core", @@ -1366,8 +1442,8 @@ dependencies = [ [[package]] name = "deno_cache" -version = "0.109.0" -source = "git+https://github.com/metatypedev/deno?branch=v2.0.6-embeddable#5bf5dcaa89967e67e5a156de02b512bf06dc3fbd" +version = "0.112.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" dependencies = [ "async-trait", "deno_core", @@ -1387,7 +1463,7 @@ dependencies = [ "base32", "deno_media_type", "deno_path_util", - "indexmap", + "indexmap 2.6.0", "log", "once_cell", "parking_lot", @@ -1400,8 +1476,8 @@ dependencies = [ [[package]] name = "deno_canvas" -version = "0.46.0" -source = "git+https://github.com/metatypedev/deno?branch=v2.0.6-embeddable#5bf5dcaa89967e67e5a156de02b512bf06dc3fbd" +version = "0.49.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" dependencies = [ "deno_core", "deno_webgpu", @@ -1412,9 +1488,9 @@ dependencies = [ [[package]] name = "deno_config" -version = "0.38.2" +version = "0.39.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "966825073480a6ac7e01977a3879d13edc8d6ea2d65ea164b37156a5fb206e9a" +checksum = "38fb809500238be2b10eee42944a47b3ac38974e1edbb47f73afcfca7df143bf" dependencies = [ "anyhow", "deno_package_json", @@ -1423,7 +1499,7 @@ dependencies = [ "glob", "ignore", "import_map", - "indexmap", + "indexmap 2.6.0", "jsonc-parser", "log", "percent-encoding", @@ -1436,19 +1512,20 @@ dependencies = [ [[package]] name = "deno_console" -version = "0.177.0" -source = "git+https://github.com/metatypedev/deno?branch=v2.0.6-embeddable#5bf5dcaa89967e67e5a156de02b512bf06dc3fbd" +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.318.0" +version = "0.323.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10cae2393219ff9278123f7b24799cdfab37c7d6561b69ca06ced115cac92111" +checksum = "a781bcfe1b5211b8497f45bf5b3dba73036b8d5d1533c1f05d26ccf0afb25a78" dependencies = [ "anyhow", + "az", "bincode", "bit-set", "bit-vec", @@ -1458,6 +1535,7 @@ dependencies = [ "deno_ops", "deno_unsync", "futures", + "indexmap 2.6.0", "libc", "memoffset", "parking_lot", @@ -1472,18 +1550,19 @@ dependencies = [ "tokio", "url", "v8", + "wasm_dep_analyzer", ] [[package]] name = "deno_core_icudata" -version = "0.0.73" +version = "0.74.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a13951ea98c0a4c372f162d669193b4c9d991512de9f2381dd161027f34b26b1" +checksum = "fe4dccb6147bb3f3ba0c7a48e993bfeb999d2c2e47a81badee80e2b370c8d695" [[package]] name = "deno_cron" -version = "0.57.0" -source = "git+https://github.com/metatypedev/deno?branch=v2.0.6-embeddable#5bf5dcaa89967e67e5a156de02b512bf06dc3fbd" +version = "0.60.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" dependencies = [ "anyhow", "async-trait", @@ -1496,8 +1575,8 @@ dependencies = [ [[package]] name = "deno_crypto" -version = "0.191.0" -source = "git+https://github.com/metatypedev/deno?branch=v2.0.6-embeddable#5bf5dcaa89967e67e5a156de02b512bf06dc3fbd" +version = "0.194.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" dependencies = [ "aes", "aes-gcm", @@ -1534,33 +1613,37 @@ dependencies = [ [[package]] name = "deno_doc" -version = "0.156.0" +version = "0.161.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2585b98d6ad76dae30bf2d7b6d71b8363cae041158b8780d14a2f4fe17590a61" +checksum = "32d994915f85e873865fc341e592080a487b0a987d06177016b2d93fd62162f8" dependencies = [ "anyhow", "cfg-if", "comrak", "deno_ast", "deno_graph", - "futures", + "deno_path_util", "handlebars", "html-escape", "import_map", - "indexmap", + "indexmap 2.6.0", "itoa", + "js-sys", "lazy_static", + "percent-encoding", "regex", "serde", + "serde-wasm-bindgen", "serde_json", - "syntect", "termcolor", + "url", + "wasm-bindgen", ] [[package]] name = "deno_fetch" -version = "0.201.0" -source = "git+https://github.com/metatypedev/deno?branch=v2.0.6-embeddable#5bf5dcaa89967e67e5a156de02b512bf06dc3fbd" +version = "0.204.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" dependencies = [ "base64 0.21.7", "bytes", @@ -1570,6 +1653,7 @@ dependencies = [ "deno_tls", "dyn-clone", "error_reporter", + "hickory-resolver", "http 1.1.0", "http-body-util", "hyper 1.5.0", @@ -1592,8 +1676,8 @@ dependencies = [ [[package]] name = "deno_ffi" -version = "0.164.0" -source = "git+https://github.com/metatypedev/deno?branch=v2.0.6-embeddable#5bf5dcaa89967e67e5a156de02b512bf06dc3fbd" +version = "0.167.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" dependencies = [ "deno_core", "deno_permissions", @@ -1613,11 +1697,12 @@ dependencies = [ [[package]] name = "deno_fs" -version = "0.87.0" -source = "git+https://github.com/metatypedev/deno?branch=v2.0.6-embeddable#5bf5dcaa89967e67e5a156de02b512bf06dc3fbd" +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", @@ -1636,9 +1721,9 @@ dependencies = [ [[package]] name = "deno_graph" -version = "0.84.1" +version = "0.86.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd4f4a14aa069087be41c2998077b0453f0191747898f96e6343f700abfc2c18" +checksum = "4c3f4be49dad28e794ff4eeb2daaf7956c97f8557097ef6f9c3ff1292e0a5c28" dependencies = [ "anyhow", "async-trait", @@ -1649,7 +1734,7 @@ dependencies = [ "encoding_rs", "futures", "import_map", - "indexmap", + "indexmap 2.6.0", "log", "monch", "once_cell", @@ -1661,12 +1746,13 @@ dependencies = [ "thiserror", "twox-hash", "url", + "wasm_dep_analyzer", ] [[package]] name = "deno_http" -version = "0.175.0" -source = "git+https://github.com/metatypedev/deno?branch=v2.0.6-embeddable#5bf5dcaa89967e67e5a156de02b512bf06dc3fbd" +version = "0.178.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" dependencies = [ "async-compression", "async-trait", @@ -1702,8 +1788,8 @@ dependencies = [ [[package]] name = "deno_io" -version = "0.87.0" -source = "git+https://github.com/metatypedev/deno?branch=v2.0.6-embeddable#5bf5dcaa89967e67e5a156de02b512bf06dc3fbd" +version = "0.90.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" dependencies = [ "async-trait", "deno_core", @@ -1724,12 +1810,13 @@ dependencies = [ [[package]] name = "deno_kv" -version = "0.85.0" -source = "git+https://github.com/metatypedev/deno?branch=v2.0.6-embeddable#5bf5dcaa89967e67e5a156de02b512bf06dc3fbd" +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", @@ -1745,7 +1832,7 @@ dependencies = [ "http-body-util", "log", "num-bigint", - "prost 0.11.9", + "prost", "prost-build", "rand", "rusqlite", @@ -1797,8 +1884,8 @@ dependencies = [ [[package]] name = "deno_napi" -version = "0.108.0" -source = "git+https://github.com/metatypedev/deno?branch=v2.0.6-embeddable#5bf5dcaa89967e67e5a156de02b512bf06dc3fbd" +version = "0.111.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" dependencies = [ "deno_core", "deno_permissions", @@ -1825,8 +1912,8 @@ dependencies = [ [[package]] name = "deno_net" -version = "0.169.0" -source = "git+https://github.com/metatypedev/deno?branch=v2.0.6-embeddable#5bf5dcaa89967e67e5a156de02b512bf06dc3fbd" +version = "0.172.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" dependencies = [ "deno_core", "deno_permissions", @@ -1843,14 +1930,15 @@ dependencies = [ [[package]] name = "deno_node" -version = "0.114.0" -source = "git+https://github.com/metatypedev/deno?branch=v2.0.6-embeddable#5bf5dcaa89967e67e5a156de02b512bf06dc3fbd" +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", @@ -1882,8 +1970,8 @@ dependencies = [ "http-body-util", "hyper 1.5.0", "hyper-util", - "idna 0.3.0", - "indexmap", + "idna 1.0.3", + "indexmap 2.6.0", "ipnetwork", "k256", "lazy-regex", @@ -1923,6 +2011,7 @@ dependencies = [ "stable_deref_trait", "thiserror", "tokio", + "tokio-eld", "url", "webpki-root-certs", "winapi", @@ -1953,13 +2042,14 @@ dependencies = [ [[package]] name = "deno_ops" -version = "0.194.0" +version = "0.199.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f760b492bd638c1dc3e992d11672c259fbe9a233162099a8347591c9e22d0391" +checksum = "a24a1f3e22029a57d3094b32070b8328eac793920b5a022027d360f085e6b245" dependencies = [ "proc-macro-rules", "proc-macro2", "quote", + "stringcase", "strum", "strum_macros", "syn 2.0.87", @@ -1973,7 +2063,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6cbc4c4d3eb0960b58e8f43f9fc2d3f620fcac9a03cd85203e08db5b04e83c1f" dependencies = [ "deno_semver", - "indexmap", + "indexmap 2.6.0", "serde", "serde_json", "thiserror", @@ -1993,8 +2083,8 @@ dependencies = [ [[package]] name = "deno_permissions" -version = "0.37.0" -source = "git+https://github.com/metatypedev/deno?branch=v2.0.6-embeddable#5bf5dcaa89967e67e5a156de02b512bf06dc3fbd" +version = "0.40.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" dependencies = [ "deno_core", "deno_path_util", @@ -2012,11 +2102,14 @@ dependencies = [ [[package]] name = "deno_resolver" -version = "0.9.0" -source = "git+https://github.com/metatypedev/deno?branch=v2.0.6-embeddable#5bf5dcaa89967e67e5a156de02b512bf06dc3fbd" +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", @@ -2028,8 +2121,8 @@ dependencies = [ [[package]] name = "deno_runtime" -version = "0.186.0" -source = "git+https://github.com/metatypedev/deno?branch=v2.0.6-embeddable#5bf5dcaa89967e67e5a156de02b512bf06dc3fbd" +version = "0.189.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" dependencies = [ "color-print", "deno_ast", @@ -2051,6 +2144,7 @@ dependencies = [ "deno_node", "deno_path_util", "deno_permissions", + "deno_telemetry", "deno_terminal 0.2.0", "deno_tls", "deno_url", @@ -2124,6 +2218,28 @@ dependencies = [ "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" @@ -2146,8 +2262,8 @@ dependencies = [ [[package]] name = "deno_tls" -version = "0.164.0" -source = "git+https://github.com/metatypedev/deno?branch=v2.0.6-embeddable#5bf5dcaa89967e67e5a156de02b512bf06dc3fbd" +version = "0.167.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" dependencies = [ "deno_core", "deno_native_certs", @@ -2196,8 +2312,8 @@ dependencies = [ [[package]] name = "deno_url" -version = "0.177.0" -source = "git+https://github.com/metatypedev/deno?branch=v2.0.6-embeddable#5bf5dcaa89967e67e5a156de02b512bf06dc3fbd" +version = "0.180.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" dependencies = [ "deno_core", "thiserror", @@ -2206,8 +2322,8 @@ dependencies = [ [[package]] name = "deno_web" -version = "0.208.0" -source = "git+https://github.com/metatypedev/deno?branch=v2.0.6-embeddable#5bf5dcaa89967e67e5a156de02b512bf06dc3fbd" +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", @@ -2225,8 +2341,8 @@ dependencies = [ [[package]] name = "deno_webgpu" -version = "0.144.0" -source = "git+https://github.com/metatypedev/deno?branch=v2.0.6-embeddable#5bf5dcaa89967e67e5a156de02b512bf06dc3fbd" +version = "0.147.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" dependencies = [ "deno_core", "raw-window-handle", @@ -2239,16 +2355,16 @@ dependencies = [ [[package]] name = "deno_webidl" -version = "0.177.0" -source = "git+https://github.com/metatypedev/deno?branch=v2.0.6-embeddable#5bf5dcaa89967e67e5a156de02b512bf06dc3fbd" +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.182.0" -source = "git+https://github.com/metatypedev/deno?branch=v2.0.6-embeddable#5bf5dcaa89967e67e5a156de02b512bf06dc3fbd" +version = "0.185.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" dependencies = [ "bytes", "deno_core", @@ -2270,8 +2386,8 @@ dependencies = [ [[package]] name = "deno_webstorage" -version = "0.172.0" -source = "git+https://github.com/metatypedev/deno?branch=v2.0.6-embeddable#5bf5dcaa89967e67e5a156de02b512bf06dc3fbd" +version = "0.175.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" dependencies = [ "deno_core", "deno_web", @@ -2300,7 +2416,7 @@ dependencies = [ "chrono", "futures", "num-bigint", - "prost 0.13.3", + "prost", "serde", "uuid", ] @@ -2320,7 +2436,7 @@ dependencies = [ "futures", "http 1.1.0", "log", - "prost 0.13.3", + "prost", "rand", "serde", "serde_json", @@ -2601,7 +2717,7 @@ dependencies = [ "anyhow", "bumpalo", "hashbrown 0.14.5", - "indexmap", + "indexmap 2.6.0", "rustc-hash", "serde", "unicode-width", @@ -2807,7 +2923,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48cede2bb1b07dd598d269f973792c43e0cd92686d3b452bd6e01d7a8eb01211" dependencies = [ "debug-ignore", - "indexmap", + "indexmap 2.6.0", "log", "thiserror", "zerocopy", @@ -3425,6 +3541,7 @@ dependencies = [ "clap", "clap_complete", "color-eyre", + "config", "dashmap", "data-encoding", "deno_core", @@ -3433,7 +3550,7 @@ dependencies = [ "educe", "futures", "futures-concurrency", - "indexmap", + "indexmap 2.6.0", "itertools 0.13.0", "json-canon", "multihash", @@ -3611,7 +3728,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -3630,7 +3747,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.1.0", - "indexmap", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -3663,6 +3780,12 @@ dependencies = [ "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" @@ -3688,6 +3811,20 @@ 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" @@ -3962,6 +4099,19 @@ dependencies = [ "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" @@ -4005,6 +4155,124 @@ 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" @@ -4013,9 +4281,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -4023,12 +4291,23 @@ dependencies = [ [[package]] name = "idna" -version = "0.4.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "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]] @@ -4073,7 +4352,7 @@ version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "351a787decc56f38d65d16d32687265045d6d6a4531b4a0e1b649def3590354e" dependencies = [ - "indexmap", + "indexmap 2.6.0", "log", "percent-encoding", "serde", @@ -4088,6 +4367,16 @@ 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" @@ -4278,6 +4567,17 @@ dependencies = [ "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" @@ -4297,6 +4597,19 @@ dependencies = [ "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" @@ -4389,12 +4702,6 @@ dependencies = [ "spin", ] -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - [[package]] name = "libc" version = "0.2.155" @@ -4517,6 +4824,12 @@ 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" @@ -4601,9 +4914,9 @@ dependencies = [ [[package]] name = "markup_fmt" -version = "0.15.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebae65c91eab3d42231232bf48107f351e5a8d511454927218c53aeb68bbdb6f" +checksum = "f303c36143671ac6c54112eb5aa95649b169dae783fdb6ead2c0e88b408c425c" dependencies = [ "aho-corasick", "css_dataset", @@ -4627,6 +4940,12 @@ 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" @@ -4758,7 +5077,7 @@ dependencies = [ "bitflags 2.6.0", "codespan-reporting", "hexf-parse", - "indexmap", + "indexmap 2.6.0", "log", "num-traits", "rustc-hash", @@ -4771,8 +5090,8 @@ dependencies = [ [[package]] name = "napi_sym" -version = "0.107.0" -source = "git+https://github.com/metatypedev/deno?branch=v2.0.6-embeddable#5bf5dcaa89967e67e5a156de02b512bf06dc3fbd" +version = "0.110.0" +source = "git+https://github.com/metatypedev/deno?branch=v2.1.2-embeddable#56aa322605a14bb3911b75376846c8624e4f4104" dependencies = [ "quote", "serde", @@ -4839,11 +5158,12 @@ dependencies = [ [[package]] name = "node_resolver" -version = "0.16.0" -source = "git+https://github.com/metatypedev/deno?branch=v2.0.6-embeddable#5bf5dcaa89967e67e5a156de02b512bf06dc3fbd" +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", @@ -5049,28 +5369,6 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" -[[package]] -name = "onig" -version = "6.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c4b31c8722ad9171c6d77d3557db078cab2bd50afcc9d09c8b315c59df8ca4f" -dependencies = [ - "bitflags 1.3.2", - "libc", - "once_cell", - "onig_sys", -] - -[[package]] -name = "onig_sys" -version = "69.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b829e3d7e9cc74c7e315ee8edb185bf4190da5acde74afd7fc59c35b1f086e7" -dependencies = [ - "cc", - "pkg-config", -] - [[package]] name = "opaque-debug" version = "0.3.1" @@ -5094,6 +5392,92 @@ 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" @@ -5337,7 +5721,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset 0.4.2", - "indexmap", + "indexmap 2.6.0", ] [[package]] @@ -5522,16 +5906,6 @@ dependencies = [ "yaml_parser", ] -[[package]] -name = "prettyplease" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" -dependencies = [ - "proc-macro2", - "syn 1.0.109", -] - [[package]] name = "prettyplease" version = "0.2.25" @@ -5613,16 +5987,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43d84d1d7a6ac92673717f9f6d1518374ef257669c24ebc5ac25d5033828be58" -[[package]] -name = "prost" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" -dependencies = [ - "bytes", - "prost-derive 0.11.9", -] - [[package]] name = "prost" version = "0.13.3" @@ -5630,42 +5994,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b0487d90e047de87f984913713b85c601c05609aad5b0df4b4573fbf69aa13f" dependencies = [ "bytes", - "prost-derive 0.13.3", + "prost-derive", ] [[package]] name = "prost-build" -version = "0.11.9" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" +checksum = "0c1318b19085f08681016926435853bbf7858f9c082d0999b80550ff5d9abe15" dependencies = [ "bytes", - "heck 0.4.1", - "itertools 0.10.5", - "lazy_static", + "heck 0.5.0", + "itertools 0.13.0", "log", "multimap", + "once_cell", "petgraph", - "prettyplease 0.1.25", - "prost 0.11.9", + "prettyplease", + "prost", "prost-types", "regex", - "syn 1.0.109", + "syn 2.0.87", "tempfile", - "which 4.4.2", -] - -[[package]] -name = "prost-derive" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" -dependencies = [ - "anyhow", - "itertools 0.10.5", - "proc-macro2", - "quote", - "syn 1.0.109", ] [[package]] @@ -5683,11 +6033,11 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.11.9" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" +checksum = "4759aa0d3a6232fb8dbdb97b61de2c20047c68aca932c7ed76da9d788508d670" dependencies = [ - "prost 0.11.9", + "prost", ] [[package]] @@ -5743,7 +6093,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d1a341ae463320e9f8f34adda49c8a85d81d4e8f34cce4397fb0350481552224" dependencies = [ "chrono", - "indexmap", + "indexmap 2.6.0", "quick-xml", "strip-ansi-escapes", "thiserror", @@ -5761,9 +6111,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -6062,9 +6412,9 @@ dependencies = [ [[package]] name = "runtimelib" -version = "0.14.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3d817764e3971867351e6103955b17d808f5330e9ef63aaaaab55bf8c664c1" +checksum = "fe23ba9967355bbb1be2fb9a8e51bd239ffdf9c791fad5a9b765122ee2bde2e4" dependencies = [ "anyhow", "base64 0.22.1", @@ -6074,6 +6424,7 @@ dependencies = [ "dirs", "futures", "glob", + "jupyter-serde", "rand", "ring", "serde", @@ -6412,6 +6763,17 @@ dependencies = [ "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" @@ -6438,7 +6800,7 @@ version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ - "indexmap", + "indexmap 2.6.0", "itoa", "memchr", "ryu", @@ -6458,9 +6820,9 @@ dependencies = [ [[package]] name = "serde_v8" -version = "0.227.0" +version = "0.232.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a8294c2223c53bed343be8b80564ece4dc0d03b643b06fa86c4ccc0e064eda0" +checksum = "5c9feae92f7293fcc1a32a86be1a399859c0637e55dad8991d5258c43f7ff4d2" dependencies = [ "num-bigint", "serde", @@ -6762,6 +7124,18 @@ dependencies = [ "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" @@ -6799,6 +7173,12 @@ dependencies = [ "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" @@ -6875,7 +7255,7 @@ checksum = "c77c112c218a09635d99a45802a81b4f341d6c28c81076aa2c29ba3bcd9151a9" dependencies = [ "anyhow", "crc", - "indexmap", + "indexmap 2.6.0", "is-macro", "once_cell", "parking_lot", @@ -6945,7 +7325,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4740e53eaf68b101203c1df0937d5161a29f3c13bceed0836ddfe245b72dd000" dependencies = [ "anyhow", - "indexmap", + "indexmap 2.6.0", "serde", "serde_json", "swc_cached", @@ -7057,7 +7437,7 @@ checksum = "65f21494e75d0bd8ef42010b47cabab9caaed8f2207570e809f6f4eb51a710d1" dependencies = [ "better_scoped_tls", "bitflags 2.6.0", - "indexmap", + "indexmap 2.6.0", "once_cell", "phf", "rustc-hash", @@ -7105,7 +7485,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98d8447ea20ef76958a8240feef95743702485a84331e6df5bdbe7e383c87838" dependencies = [ "dashmap", - "indexmap", + "indexmap 2.6.0", "once_cell", "petgraph", "rustc-hash", @@ -7150,7 +7530,7 @@ checksum = "76c76d8b9792ce51401d38da0fa62158d61f6d80d16d68fe5b03ce4bf5fba383" dependencies = [ "base64 0.21.7", "dashmap", - "indexmap", + "indexmap 2.6.0", "once_cell", "serde", "sha1", @@ -7190,7 +7570,7 @@ version = "0.134.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "029eec7dd485923a75b5a45befd04510288870250270292fc2c1b3a9e7547408" dependencies = [ - "indexmap", + "indexmap 2.6.0", "num_cpus", "once_cell", "rustc-hash", @@ -7235,7 +7615,7 @@ version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357e2c97bb51431d65080f25b436bc4e2fc1a7f64a643bc21a8353e478dc799f" dependencies = [ - "indexmap", + "indexmap 2.6.0", "petgraph", "rustc-hash", "swc_common", @@ -7310,6 +7690,12 @@ dependencies = [ "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" @@ -7333,26 +7719,6 @@ dependencies = [ "syn 2.0.87", ] -[[package]] -name = "syntect" -version = "5.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "874dcfa363995604333cf947ae9f751ca3af4522c60886774c4963943b4746b1" -dependencies = [ - "bincode", - "bitflags 1.3.2", - "flate2", - "fnv", - "once_cell", - "onig", - "regex-syntax 0.8.5", - "serde", - "serde_derive", - "serde_json", - "thiserror", - "walkdir", -] - [[package]] name = "tap" version = "1.0.1" @@ -7488,6 +7854,16 @@ 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" @@ -7522,6 +7898,16 @@ dependencies = [ "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" @@ -7570,9 +7956,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" dependencies = [ "futures-core", "pin-project-lite", @@ -7605,6 +7991,36 @@ 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" @@ -7613,11 +8029,16 @@ 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]] @@ -7961,12 +8382,12 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.4.1" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", - "idna 0.4.0", + "idna 1.0.3", "percent-encoding", "serde", ] @@ -7989,12 +8410,24 @@ 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" @@ -8014,9 +8447,9 @@ dependencies = [ [[package]] name = "v8" -version = "0.106.0" +version = "130.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a381badc47c6f15acb5fe0b5b40234162349ed9d4e4fd7c83a7f5547c0fc69c5" +checksum = "c23b5c2caff00209b03a716609b275acae94b02dd3b63c4648e7232a84a8402f" dependencies = [ "bindgen", "bitflags 2.6.0", @@ -8037,7 +8470,7 @@ checksum = "97599c400fc79925922b58303e98fcb8fa88f573379a08ddb652e72cbd2e70f6" dependencies = [ "bitflags 2.6.0", "encoding_rs", - "indexmap", + "indexmap 2.6.0", "num-bigint", "serde", "thiserror", @@ -8193,6 +8626,15 @@ 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" @@ -8233,7 +8675,7 @@ dependencies = [ "cfg_aliases 0.1.1", "codespan-reporting", "document-features", - "indexmap", + "indexmap 2.6.0", "log", "naga", "once_cell", @@ -8567,6 +9009,18 @@ 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" @@ -8739,9 +9193,9 @@ dependencies = [ [[package]] name = "zeromq" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb0560d00172817b7f7c2265060783519c475702ae290b154115ca75e976d4d0" +checksum = "6a4528179201f6eecf211961a7d3276faa61554c82651ecc66387f68fc3004bd" dependencies = [ "async-trait", "asynchronous-codec", @@ -8764,6 +9218,28 @@ dependencies = [ "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" @@ -8775,7 +9251,7 @@ dependencies = [ "crossbeam-utils", "displaydoc", "flate2", - "indexmap", + "indexmap 2.6.0", "memchr", "thiserror", ] diff --git a/Cargo.toml b/Cargo.toml index 91f09b0..374b7bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,10 +9,10 @@ edition = "2021" [workspace.dependencies] denort = { path = "src/denort" } -deno = { git = "https://github.com/metatypedev/deno", branch = "v2.0.6-embeddable" } +deno = { git = "https://github.com/metatypedev/deno", branch = "v2.1.2-embeddable" } # needed to get deno_core::op2 working -# must track version used by deno -deno_core = "=0.318.0" +# WARN: must track version used by deno +deno_core = "=0.323.0" educe = "0.6" @@ -28,7 +28,7 @@ tracing-unwrap = "1.0" once_cell = "1" -# version must match on clap in `deno` +# WARN: version must match on clap in `deno` clap = "=4.5" clap_complete = "=4.5.24" diff --git a/deno.jsonc b/deno.jsonc index fdbc2ba..0bcb7ce 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -1,6 +1,6 @@ { "tasks": { - "test": "cargo x test tests/*", + "test": "cargo build -p ghjk && deno test --parallel --unstable-worker-options --unstable-kv -A tests/*", "self": "deno run -A --unstable-kv --unstable-worker-options main.ts ", "cache": "deno cache deps/*", "check": "deno run -A ./scripts/check.ts", diff --git a/deno.lock b/deno.lock index 6d7581e..a25e27a 100644 --- a/deno.lock +++ b/deno.lock @@ -1,11 +1,8 @@ { "version": "4", "specifiers": { - "jsr:@david/dax@0.40.1": "0.40.1", "jsr:@david/dax@0.41.0": "0.41.0", - "jsr:@david/which@0.3": "0.3.0", "jsr:@david/which@~0.4.1": "0.4.1", - "jsr:@ghjk/dax@0.40.2-alpha-ghjk": "0.40.2-alpha-ghjk", "jsr:@std/assert@0.221": "0.221.0", "jsr:@std/bytes@0.221": "0.221.0", "jsr:@std/fmt@0.221": "0.221.0", @@ -15,37 +12,16 @@ "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:@livekit/rtc-node@0.11.1": "0.11.1", "npm:@noble/hashes@1.4.0": "1.4.0", - "npm:@types/node@*": "18.16.19", - "npm:livekit-server-sdk@2.7.2": "2.7.2", - "npm:lodash@*": "4.17.21", - "npm:mathjs@11.11.1": "11.11.1", "npm:multiformats@13.1.0": "13.1.0", - "npm:pg@*": "8.12.0", - "npm:validator@*": "13.12.0", - "npm:zod-validation-error@*": "3.1.0_zod@3.23.3", - "npm:zod-validation-error@3.2.0": "3.2.0_zod@3.23.3", - "npm:zod-validation-error@3.3.0": "3.3.0_zod@3.23.3", "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.40.1": { - "integrity": "0c71d32a0484d3904f586417995f8ec26d45144f0eba95d3e5bb03b640b6df59", - "dependencies": [ - "jsr:@david/which@0.3", - "jsr:@std/fmt", - "jsr:@std/fs", - "jsr:@std/io@0.221.0", - "jsr:@std/path@0.221.0", - "jsr:@std/streams" - ] - }, "@david/dax@0.41.0": { "integrity": "9e1ecf66a0415962cc8ad3ba4e3fa93ce0f1a1cc797dd95c36fdfb6977dc7fc8", "dependencies": [ - "jsr:@david/which@~0.4.1", + "jsr:@david/which", "jsr:@std/fmt", "jsr:@std/fs", "jsr:@std/io@0.221.0", @@ -53,23 +29,9 @@ "jsr:@std/streams" ] }, - "@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", - "jsr:@std/fs", - "jsr:@std/io@0.221.0", - "jsr:@std/path@0.221.0", - "jsr:@std/streams" - ] - }, "@std/assert@0.221.0": { "integrity": "a5f1aa6e7909dbea271754fd4ab3f4e687aeff4873b4cef9a320af813adb489a" }, @@ -107,239 +69,18 @@ } }, "npm": { - "@babel/runtime@7.24.7": { - "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==", - "dependencies": [ - "regenerator-runtime" - ] - }, - "@bufbuild/protobuf@1.10.0": { - "integrity": "sha512-QDdVFLoN93Zjg36NoQPZfsVH9tZew7wKDKyV5qRdj8ntT4wQCOradQjRaTdwMhWUYsgKsvCINKKm87FdEk96Ag==" - }, - "@bufbuild/protobuf@2.2.2": { - "integrity": "sha512-UNtPCbrwrenpmrXuRwn9jYpPoweNXj8X5sMvYgsqYyaH8jQ6LfUJSk3dJLnBK+6sfYPrF4iAIo5sd5HQ+tg75A==" - }, - "@livekit/mutex@1.1.0": { - "integrity": "sha512-XRLG+z/0uoyDioupjUiskjI06Y51U/IXVPJn7qJ+R3J75XX01irYVBM9MpxeJahpVoe9QhU4moIEolX+HO9U9g==" - }, - "@livekit/protocol@1.27.1": { - "integrity": "sha512-ISEp7uWdV82mtCR1eyHFTzdRZTVbe2+ZztjmjiMPzR/KPrI1Ma/u5kLh87NNuY3Rn8wv1VlEvGHHsFjQ+dKVUw==", - "dependencies": [ - "@bufbuild/protobuf@1.10.0" - ] - }, - "@livekit/rtc-node-darwin-arm64@0.11.1": { - "integrity": "sha512-M+Ui87H06ae19GGI7r937dS6hI84MBBTQAkkNlL7qd+pvdCAk25u0FYa8r4SOElKJ0VR3AbzeDoXTihLgpvjMg==" - }, - "@livekit/rtc-node-darwin-x64@0.11.1": { - "integrity": "sha512-7G92fyuK2p+jdTH2cUJTNeAmtknTGsXuy0xbI727V7VzQvHFDXULCExRlgwn4t9TxvNlIjUpiltiQ6RCSai6zw==" - }, - "@livekit/rtc-node-linux-arm64-gnu@0.11.1": { - "integrity": "sha512-vqZN9+87Pvxit7auYVW69M+GvUPnf+EwipIJ92GgCJA3Ir1Tcceu5ud5/Ic+0FzSoV0cotVVlQNm74F0tQvyCg==" - }, - "@livekit/rtc-node-linux-x64-gnu@0.11.1": { - "integrity": "sha512-smHZUMfgILQh6/eoauYNe/VlKwQCp4/4jWxiIADHY+mtDtVSvQ9zB6y4GP8FrpohRwFWesKCUpvPBypU0Icrng==" - }, - "@livekit/rtc-node-win32-x64-msvc@0.11.1": { - "integrity": "sha512-bTWVtb+UiRPFjiuhrqq40gt5vs5mMPTa1e+kd2jGQPTOlKZPLArQ0WgFcep2TAy1zmcpOgfeM1XRPVFhZl7G1A==" - }, - "@livekit/rtc-node@0.11.1": { - "integrity": "sha512-EFw+giPll12fcXATZpN2zKkE3umYJAdHvfjW+Yu0aBjwfxbUBXu8rz6le2CzDNvGmRwR888DSZXFZfYikwZgiw==", - "dependencies": [ - "@bufbuild/protobuf@2.2.2", - "@livekit/mutex", - "@livekit/rtc-node-darwin-arm64", - "@livekit/rtc-node-darwin-x64", - "@livekit/rtc-node-linux-arm64-gnu", - "@livekit/rtc-node-linux-x64-gnu", - "@livekit/rtc-node-win32-x64-msvc", - "@livekit/typed-emitter" - ] - }, - "@livekit/typed-emitter@3.0.0": { - "integrity": "sha512-9bl0k4MgBPZu3Qu3R3xy12rmbW17e3bE9yf4YY85gJIQ3ezLEj/uzpKHWBsLaDoL5Mozz8QCgggwIBudYQWeQg==" - }, "@noble/hashes@1.4.0": { "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==" }, - "@types/node@18.16.19": { - "integrity": "sha512-IXl7o+R9iti9eBW4Wg2hx1xQDig183jj7YLn8F7udNceyfkbn1ZxmzZXuak20gR40D7pIkIY1kYGx5VIGbaHKA==" - }, - "camelcase-keys@9.1.3": { - "integrity": "sha512-Rircqi9ch8AnZscQcsA1C47NFdaO3wukpmIRzYcDOrmvgt78hM/sj5pZhZNec2NM12uk5vTwRHZ4anGcrC4ZTg==", - "dependencies": [ - "camelcase", - "map-obj", - "quick-lru", - "type-fest" - ] - }, - "camelcase@8.0.0": { - "integrity": "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==" - }, - "complex.js@2.1.1": { - "integrity": "sha512-8njCHOTtFFLtegk6zQo0kkVX1rngygb/KQI6z1qZxlFI3scluC+LVTCFbrkWjBv4vvLlbQ9t88IPMC6k95VTTg==" - }, - "decimal.js@10.4.3": { - "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==" - }, - "escape-latex@1.2.0": { - "integrity": "sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw==" - }, - "fraction.js@4.3.4": { - "integrity": "sha512-pwiTgt0Q7t+GHZA4yaLjObx4vXmmdcS0iSJ19o8d/goUGgItX9UZWKWNnLHehxviD8wU2IWRsnR8cD5+yOJP2Q==" - }, - "javascript-natural-sort@0.7.1": { - "integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==" - }, - "jose@5.9.6": { - "integrity": "sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==" - }, - "livekit-server-sdk@2.7.2": { - "integrity": "sha512-qDNRXeo+WMnY5nKSug7KHJ9er9JIuKi+r7H9ZaSBbmbaOt62i0b4BrHBMFSMr8pAuWzuSxihCFa29q5QvFc5fw==", - "dependencies": [ - "@livekit/protocol", - "camelcase-keys", - "jose" - ] - }, - "lodash@4.17.21": { - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "map-obj@5.0.0": { - "integrity": "sha512-2L3MIgJynYrZ3TYMriLDLWocz15okFakV6J12HXvMXDHui2x/zgChzg1u9mFFGbbGWE+GsLpQByt4POb9Or+uA==" - }, - "mathjs@11.11.1": { - "integrity": "sha512-uWrwMrhU31TCqHKmm1yFz0C352njGUVr/I1UnpMOxI/VBTTbCktx/mREUXx5Vyg11xrFdg/F3wnMM7Ql/csVsQ==", - "dependencies": [ - "@babel/runtime", - "complex.js", - "decimal.js", - "escape-latex", - "fraction.js", - "javascript-natural-sort", - "seedrandom", - "tiny-emitter", - "typed-function" - ] - }, "multiformats@13.1.0": { "integrity": "sha512-HzdtdBwxsIkzpeXzhQ5mAhhuxcHbjEHH+JQoxt7hG/2HGFjjwyolLo7hbaexcnhoEuV4e0TNJ8kkpMjiEYY4VQ==" }, - "pg-cloudflare@1.1.1": { - "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==" - }, - "pg-connection-string@2.6.4": { - "integrity": "sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA==" - }, - "pg-int8@1.0.1": { - "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" - }, - "pg-pool@3.6.2_pg@8.12.0": { - "integrity": "sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg==", - "dependencies": [ - "pg" - ] - }, - "pg-protocol@1.6.1": { - "integrity": "sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg==" - }, - "pg-types@2.2.0": { - "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", - "dependencies": [ - "pg-int8", - "postgres-array", - "postgres-bytea", - "postgres-date", - "postgres-interval" - ] - }, - "pg@8.12.0": { - "integrity": "sha512-A+LHUSnwnxrnL/tZ+OLfqR1SxLN3c/pgDztZ47Rpbsd4jUytsTtwQo/TLPRzPJMp/1pbhYVhH9cuSZLAajNfjQ==", - "dependencies": [ - "pg-cloudflare", - "pg-connection-string", - "pg-pool", - "pg-protocol", - "pg-types", - "pgpass" - ] - }, - "pgpass@1.0.5": { - "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", - "dependencies": [ - "split2" - ] - }, - "postgres-array@2.0.0": { - "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" - }, - "postgres-bytea@1.0.0": { - "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==" - }, - "postgres-date@1.0.7": { - "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==" - }, - "postgres-interval@1.2.0": { - "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", - "dependencies": [ - "xtend" - ] - }, - "quick-lru@6.1.2": { - "integrity": "sha512-AAFUA5O1d83pIHEhJwWCq/RQcRukCkn/NSm2QsTEMle5f2hP0ChI2+3Xb051PZCkLryI/Ir1MVKviT2FIloaTQ==" - }, - "regenerator-runtime@0.14.1": { - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" - }, - "seedrandom@3.0.5": { - "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==" - }, - "split2@4.2.0": { - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==" - }, - "tiny-emitter@2.1.0": { - "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==" - }, - "type-fest@4.26.1": { - "integrity": "sha512-yOGpmOAL7CkKe/91I5O3gPICmJNLJ1G4zFYVAsRHg7M64biSnPtRj0WNQt++bRkjYOqjWXrhnUw1utzmVErAdg==" - }, - "typed-function@4.2.1": { - "integrity": "sha512-EGjWssW7Tsk4DGfE+5yluuljS1OGYWiI1J6e8puZz9nTMM51Oug8CD5Zo4gWMsOhq5BI+1bF+rWTm4Vbj3ivRA==" - }, - "validator@13.12.0": { - "integrity": "sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==" - }, - "xtend@4.0.2": { - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" - }, - "zod-validation-error@3.1.0_zod@3.23.3": { - "integrity": "sha512-zujS6HqJjMZCsvjfbnRs7WI3PXN39ovTcY1n8a+KTm4kOH0ZXYsNiJkH1odZf4xZKMkBDL7M2rmQ913FCS1p9w==", - "dependencies": [ - "zod@3.23.3" - ] - }, - "zod-validation-error@3.2.0_zod@3.23.3": { - "integrity": "sha512-cYlPR6zuyrgmu2wRTdumEAJGuwI7eHVHGT+VyneAQxmRAKtGRL1/7pjz4wfLhz4J05f5qoSZc3rGacswgyTjjw==", - "dependencies": [ - "zod@3.23.3" - ] - }, - "zod-validation-error@3.3.0_zod@3.23.3": { - "integrity": "sha512-Syib9oumw1NTqEv4LT0e6U83Td9aVRk9iTXPUQr1otyV1PuXQKOvOwhMNqZIq5hluzHP2pMgnOmHEo7kPdI2mw==", - "dependencies": [ - "zod@3.23.3" - ] - }, "zod-validation-error@3.4.0_zod@3.23.8": { "integrity": "sha512-ZOPR9SVY6Pb2qqO5XHt+MkkTRxGXb4EVtnjc9JpXUOtUB1T9Ru7mZOT361AN3MsetVe7R0a1KZshJDZdgp9miQ==", "dependencies": [ - "zod@3.23.8" + "zod" ] }, - "zod@3.23.3": { - "integrity": "sha512-tPvq1B/2Yu/dh2uAIH2/BhUlUeLIUvAjr6dpL/75I0pCYefHgjhXk1o1Kob3kTU8C7yU1j396jFHlsVWFi9ogg==" - }, "zod@3.23.8": { "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==" } @@ -357,55 +98,10 @@ "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.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", - "https://deno.land/std@0.213.0/assert/_diff.ts": "dcc63d94ca289aec80644030cf88ccbf7acaa6fbd7b0f22add93616b36593840", - "https://deno.land/std@0.213.0/assert/_format.ts": "0ba808961bf678437fb486b56405b6fefad2cf87b5809667c781ddee8c32aff4", "https://deno.land/std@0.213.0/assert/assert.ts": "bec068b2fccdd434c138a555b19a2c2393b71dfaada02b7d568a01541e67cdc5", - "https://deno.land/std@0.213.0/assert/assert_almost_equals.ts": "8b96b7385cc117668b0720115eb6ee73d04c9bcb2f5d2344d674918c9113688f", - "https://deno.land/std@0.213.0/assert/assert_array_includes.ts": "1688d76317fd45b7e93ef9e2765f112fdf2b7c9821016cdfb380b9445374aed1", - "https://deno.land/std@0.213.0/assert/assert_equals.ts": "4497c56fe7d2993b0d447926702802fc0becb44e319079e8eca39b482ee01b4e", - "https://deno.land/std@0.213.0/assert/assert_exists.ts": "24a7bf965e634f909242cd09fbaf38bde6b791128ece08e33ab08586a7cc55c9", - "https://deno.land/std@0.213.0/assert/assert_false.ts": "6f382568e5128c0f855e5f7dbda8624c1ed9af4fcc33ef4a9afeeedcdce99769", - "https://deno.land/std@0.213.0/assert/assert_greater.ts": "4945cf5729f1a38874d7e589e0fe5cc5cd5abe5573ca2ddca9d3791aa891856c", - "https://deno.land/std@0.213.0/assert/assert_greater_or_equal.ts": "573ed8823283b8d94b7443eb69a849a3c369a8eb9666b2d1db50c33763a5d219", - "https://deno.land/std@0.213.0/assert/assert_instance_of.ts": "72dc1faff1e248692d873c89382fa1579dd7b53b56d52f37f9874a75b11ba444", - "https://deno.land/std@0.213.0/assert/assert_is_error.ts": "6596f2b5ba89ba2fe9b074f75e9318cda97a2381e59d476812e30077fbdb6ed2", - "https://deno.land/std@0.213.0/assert/assert_less.ts": "2b4b3fe7910f65f7be52212f19c3977ecb8ba5b2d6d0a296c83cde42920bb005", - "https://deno.land/std@0.213.0/assert/assert_less_or_equal.ts": "b93d212fe669fbde959e35b3437ac9a4468f2e6b77377e7b6ea2cfdd825d38a0", - "https://deno.land/std@0.213.0/assert/assert_match.ts": "ec2d9680ed3e7b9746ec57ec923a17eef6d476202f339ad91d22277d7f1d16e1", - "https://deno.land/std@0.213.0/assert/assert_not_equals.ts": "f3edda73043bc2c9fae6cbfaa957d5c69bbe76f5291a5b0466ed132c8789df4c", - "https://deno.land/std@0.213.0/assert/assert_not_instance_of.ts": "8f720d92d83775c40b2542a8d76c60c2d4aeddaf8713c8d11df8984af2604931", - "https://deno.land/std@0.213.0/assert/assert_not_match.ts": "b4b7c77f146963e2b673c1ce4846473703409eb93f5ab0eb60f6e6f8aeffe39f", - "https://deno.land/std@0.213.0/assert/assert_not_strict_equals.ts": "da0b8ab60a45d5a9371088378e5313f624799470c3b54c76e8b8abeec40a77be", - "https://deno.land/std@0.213.0/assert/assert_object_match.ts": "e85e5eef62a56ce364c3afdd27978ccab979288a3e772e6855c270a7b118fa49", - "https://deno.land/std@0.213.0/assert/assert_rejects.ts": "e9e0c8d9c3e164c7ac962c37b3be50577c5a2010db107ed272c4c1afb1269f54", - "https://deno.land/std@0.213.0/assert/assert_strict_equals.ts": "0425a98f70badccb151644c902384c12771a93e65f8ff610244b8147b03a2366", - "https://deno.land/std@0.213.0/assert/assert_string_includes.ts": "dfb072a890167146f8e5bdd6fde887ce4657098e9f71f12716ef37f35fb6f4a7", - "https://deno.land/std@0.213.0/assert/assert_throws.ts": "edddd86b39606c342164b49ad88dd39a26e72a26655e07545d172f164b617fa7", "https://deno.land/std@0.213.0/assert/assertion_error.ts": "9f689a101ee586c4ce92f52fa7ddd362e86434ffdf1f848e45987dc7689976b8", - "https://deno.land/std@0.213.0/assert/equal.ts": "fae5e8a52a11d3ac694bbe1a53e13a7969e3f60791262312e91a3e741ae519e2", - "https://deno.land/std@0.213.0/assert/fail.ts": "f310e51992bac8e54f5fd8e44d098638434b2edb802383690e0d7a9be1979f1c", - "https://deno.land/std@0.213.0/assert/mod.ts": "325df8c0683ad83a873b9691aa66b812d6275fc9fec0b2d180ac68a2c5efed3b", - "https://deno.land/std@0.213.0/assert/unimplemented.ts": "47ca67d1c6dc53abd0bd729b71a31e0825fc452dbcd4fde4ca06789d5644e7fd", - "https://deno.land/std@0.213.0/assert/unreachable.ts": "38cfecb95d8b06906022d2f9474794fca4161a994f83354fd079cac9032b5145", - "https://deno.land/std@0.213.0/async/_util.ts": "64f8d0da48f908c651736317a36e97890ea9ea22a5e281c8acf9ee6cafbb6de9", - "https://deno.land/std@0.213.0/async/abortable.ts": "87bbc086dfdbb3556fe47d12038dc3919b4f717b3660abb21f800e020c159664", - "https://deno.land/std@0.213.0/async/deadline.ts": "65cf43eb30948f5122fa66a0d6c0fc166af23621632b6e440303efe164e8a0db", - "https://deno.land/std@0.213.0/async/debounce.ts": "214cee25fb32ee8df89775f0c81902aa52f2a6c1fa13afa3fddbb6ddccc1446d", - "https://deno.land/std@0.213.0/async/delay.ts": "8e1d18fe8b28ff95885e2bc54eccec1713f57f756053576d8228e6ca110793ad", - "https://deno.land/std@0.213.0/async/mod.ts": "02ba6a7d065481b6318d0783ad7243426e4f1bc4cdee0d1b6460bf73e9eab3e3", - "https://deno.land/std@0.213.0/async/mux_async_iterator.ts": "33aa184f27fd2be1467dab3785dfdf525c8b8acd150a049331f0fdf927a17dda", - "https://deno.land/std@0.213.0/async/pool.ts": "2b972e3643444b73f6a8bcdd19799a2d0821b28a45fbe47fd333223eb84327f0", - "https://deno.land/std@0.213.0/async/retry.ts": "718335f89d1fbd2156109b05d2399a2b47c848a5a8f7237640538902526b38f7", - "https://deno.land/std@0.213.0/async/tee.ts": "34373c58950b7ac5950632dc8c9908076abeefcc9032d6299fff92194c284fbd", "https://deno.land/std@0.213.0/bytes/concat.ts": "9cac3b4376afbef98ff03588eb3cf948e0d1eb6c27cfe81a7651ab6dd3adc54a", "https://deno.land/std@0.213.0/bytes/copy.ts": "f29c03168853720dfe82eaa57793d0b9e3543ebfe5306684182f0f1e3bfd422a", "https://deno.land/std@0.213.0/fmt/colors.ts": "aeaee795471b56fc62a3cb2e174ed33e91551b535f44677f6320336aabb54fbb", @@ -619,12 +315,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", @@ -633,12 +323,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", @@ -704,56 +388,7 @@ "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://esm.sh/jszip@3.7.1": "f3872a819b015715edb05f81d973b5cd05d3d213d8eb28293ca5471fe7a71773", "https://esm.sh/v135/jszip@3.7.1/denonext/jszip.mjs": "d31d7f9e0de9c6db3c07ca93f7301b756273d4dccb41b600461978fc313504c9" } diff --git a/ghjk.ts b/ghjk.ts index 065fe27..343de45 100644 --- a/ghjk.ts +++ b/ghjk.ts @@ -15,7 +15,7 @@ config({ }); env("main").vars({ - RUST_LOG: "debug,deno=info,denort=trace,swc_ecma_transforms_base=info", + RUST_LOG: "info,deno=info,denort=trace,swc_ecma_transforms_base=info", }); env("_rust") @@ -50,7 +50,7 @@ if (Deno.build.os == "linux" && !Deno.env.has("NO_MOLD")) { // these are just for quick testing install(); -const DENO_VERSION = "2.0.6"; +const DENO_VERSION = "2.1.2"; // these are used for developing ghjk install( @@ -126,6 +126,12 @@ task( [/(GHJK_VERSION="\$\{GHJK_VERSION:-v).*(\}")/, GHJK_VERSION], [/(DENO_VERSION="\$\{DENO_VERSION:-v).*(\}")/, DENO_VERSION], ], + "./tests/test.Dockerfile": [ + [/(ARG DENO_VERSION=).*()/, DENO_VERSION], + ], + "./tests/test-alpine.Dockerfile": [ + [/(ARG DENO_VERSION=).*()/, DENO_VERSION], + ], "./docs/*.md": [ [ /(.*\/metatypedev\/ghjk\/v)[^/]*(\/.*)/, @@ -142,6 +148,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 @@ -162,4 +175,5 @@ task( }, ); }, + { inherits:false } ); diff --git a/install.sh b/install.sh index 30c3475..daf29c0 100755 --- a/install.sh +++ b/install.sh @@ -5,7 +5,7 @@ set -e -u GHJK_VERSION="${GHJK_VERSION:-v0.3.0}" 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:-v2.0.6}" +DENO_VERSION="${DENO_VERSION:-v2.1.2}" # make sure the version is prepended with v if [ "${DENO_VERSION#"v"}" = "$DENO_VERSION" ]; then diff --git a/install/mod.ts b/install/mod.ts index 3210506..d42a52b 100644 --- a/install/mod.ts +++ b/install/mod.ts @@ -39,7 +39,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"), @@ -105,33 +105,16 @@ async function filterAddContent( interface InstallArgs { homeDir: string; ghjkShareDir: string; + ghjkConfigDir: 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; } export const defaultInstallArgs: InstallArgs = { @@ -139,16 +122,7 @@ export const defaultInstallArgs: InstallArgs = { homeDir: dirs().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, + ghjkConfigDir: $.path(dirs().configDir).toString(), }; const shellConfig: Record = { diff --git a/src/ghjk/Cargo.toml b/src/ghjk/Cargo.toml index 605a9ea..834f567 100644 --- a/src/ghjk/Cargo.toml +++ b/src/ghjk/Cargo.toml @@ -63,6 +63,8 @@ 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" diff --git a/src/ghjk/cli.rs b/src/ghjk/cli.rs index 83fcdc6..6d8af66 100644 --- a/src/ghjk/cli.rs +++ b/src/ghjk/cli.rs @@ -5,14 +5,21 @@ use clap::builder::styling::AnsiColor; use crate::interlude::*; use crate::systems::{CliCommandAction, SystemCliCommand}; -use crate::{host, systems, utils, Config}; +use crate::{host, systems, utils}; + +#[derive(Debug)] +pub struct Config { + pub ghjkfile_path: Option, + pub ghjkdir_path: Option, + pub share_dir_path: PathBuf, +} const DENO_UNSTABLE_FLAGS: &[&str] = &["worker-options", "kv"]; pub async fn cli() -> Res { let cwd = std::env::current_dir()?; - let config = { + let (config, deno_lockfile_path) = { let ghjk_dir_path = match std::env::var("GHJK_DIR") { Ok(path) => Some(PathBuf::from(path)), Err(std::env::VarError::NotUnicode(os_str)) => Some(PathBuf::from(os_str)), @@ -40,10 +47,14 @@ pub async fn cli() -> Res { None => utils::find_entry_recursive(&cwd, "ghjk.ts").await?, }; - let ghjkfile_path = if let Some(path) = ghjkfile_path { - Some(tokio::fs::canonicalize(path).await?) + let (ghjkfile_path, ghjk_dir_path) = if let Some(path) = ghjkfile_path { + let file_path = tokio::fs::canonicalize(path).await?; + // if ghjkfile var is set, set the GHJK_DIR overriding + // any set by the user + let dir_path = file_path.parent().unwrap().join(".ghjk"); + (Some(file_path), Some(dir_path)) } else { - None + (None, ghjk_dir_path) }; if ghjk_dir_path.is_none() && ghjkfile_path.is_none() { @@ -60,11 +71,25 @@ pub async fn cli() -> Res { .data_local_dir() .join("ghjk"), }; - Config { - ghjkfile_path, - ghjkdir_path: ghjk_dir_path, - share_dir_path, - } + + let deno_lockfile_path = match std::env::var("GHJK_DENO_LOCKFILE") { + Ok(str) if str == "off" => None, + Ok(path) => Some(PathBuf::from(path)), + Err(std::env::VarError::NotUnicode(os_str)) => Some(PathBuf::from(os_str)), + Err(std::env::VarError::NotPresent) => match &ghjk_dir_path { + Some(path) => Some(path.join("deno.lock")), + None => None, + }, + }; + + ( + Config { + ghjkfile_path, + ghjkdir_path: ghjk_dir_path, + share_dir_path, + }, + deno_lockfile_path, + ) }; let Some(quick_err) = try_quick_cli(&config).await? else { @@ -75,7 +100,11 @@ pub async fn cli() -> Res { quick_err.exit(); }; + // TODO: create ghjk_dir_path if it doens't exist + // TODO: create .gitignore file as well + let deno_cx = denort::worker( + // TODO: DENO_FLAGS param simlar to V8_FLAGS denort::deno::args::Flags { unstable_config: denort::deno::args::UnstableConfig { features: DENO_UNSTABLE_FLAGS @@ -85,6 +114,8 @@ pub async fn cli() -> Res { .collect(), ..default() }, + no_lock: deno_lockfile_path.is_none(), + lock: deno_lockfile_path.map(|path| path.to_string_lossy().into()), ..default() }, Some(Arc::new(Vec::new)), @@ -168,6 +199,9 @@ pub async fn cli() -> Res { _ = commands.action(&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; @@ -236,6 +270,7 @@ pub async fn try_quick_cli(config: &Config) -> Res> { ))); } } + QuickComands::Deno { .. } => unreachable!("deno quick cli will have prevented this"), } Ok(None) @@ -265,6 +300,11 @@ enum QuickComands { #[command(subcommand)] commands: PrintCommands, }, + /// Access the deno cli + Deno { + #[arg(raw(true))] + args: String, + }, } #[derive(clap::Subcommand, Debug)] @@ -413,3 +453,56 @@ async fn action_for_match( 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 Some(first) = argv.get(0) else { + return None; + }; + 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/main.rs b/src/ghjk/main.rs index 0daf983..2f99b9e 100644 --- a/src/ghjk/main.rs +++ b/src/ghjk/main.rs @@ -32,6 +32,7 @@ mod interlude { mod host; mod cli; +mod config; mod ext; mod log; mod systems; @@ -40,12 +41,18 @@ 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(); @@ -68,10 +75,3 @@ pub struct GhjkCtx { ghjk_dir_path: PathBuf, share_dir_path: PathBuf, } - -#[derive(Debug)] -struct Config { - ghjkfile_path: Option, - ghjkdir_path: Option, - share_dir_path: PathBuf, -} diff --git a/tests/test-alpine.Dockerfile b/tests/test-alpine.Dockerfile index e965518..c081d7a 100644 --- a/tests/test-alpine.Dockerfile +++ b/tests/test-alpine.Dockerfile @@ -1,6 +1,6 @@ -ARG DENO_V=1.42.1 +ARG DENO_VERSION=2.1.2 -FROM docker.io/denoland/deno:alpine-${DENO_V} +FROM docker.io/denoland/deno:alpine-${DENO_VERSION} ARG BASH_V=5.2.21-r0 ARG FISH_V=3.6.3-r0 diff --git a/tests/test.Dockerfile b/tests/test.Dockerfile index 3e4e2ba..57c9d24 100644 --- a/tests/test.Dockerfile +++ b/tests/test.Dockerfile @@ -1,6 +1,6 @@ -ARG DENO_VERSION=1.44.2 +ARG DENO_VERSION=2.1.2 -FROM denoland/deno:bin-$DENO_VERSION AS deno +FROM docker.io/denoland/deno:bin-$DENO_VERSION AS deno FROM docker.io/library/debian:12-slim diff --git a/tests/utils.ts b/tests/utils.ts index 81c9af2..e471437 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -68,12 +68,21 @@ export async function dockerE2eTest(testCase: E2eTestCase) { .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); + if (dockerCmd[0] == "podman") { + await $ + .raw`${dockerCmd} buildah build ${dockerPlatform} ${ + Object.entries(env).map(([key, val]) => ["--build-arg", `${key}=${val}`]) + } --tag '${tag}' --network=host -- -f- .` + .env(env) + .stdinText(dFile); + } else { + 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 ${[ diff --git a/utils/mod.ts b/utils/mod.ts index 0082d8b..330f085 100644 --- a/utils/mod.ts +++ b/utils/mod.ts @@ -325,7 +325,9 @@ export function dirs() { } return { homeDir: home, + // FIXME: use proper xdg dirs shareDir: $.path(home).resolve(".local", "share"), + configDir: $.path(home).resolve(".config", "ghjk"), }; } From 5455ef034626984f061cc09c3cc6cfe3db88ba9b Mon Sep 17 00:00:00 2001 From: Yohe-Am <56622350+Yohe-Am@users.noreply.github.com> Date: Mon, 9 Dec 2024 22:12:39 +0300 Subject: [PATCH 04/13] wip: configs --- deno.lock | 40 ++++ ghjk.ts | 4 +- install/bash-preexec.sh | 353 +++++++++++++++++++++++++++++++++++ install/hook.fish | 1 + install/hook.sh | 2 +- src/deno_systems/bindings.ts | 19 +- src/ghjk/cli.rs | 142 +++----------- src/ghjk/config.rs | 272 +++++++++++++++++++++++++++ src/ghjk/host.rs | 13 +- src/ghjk/host/deno.rs | 1 + src/ghjk/main.rs | 5 +- src/ghjk/systems/deno.rs | 40 ++-- 12 files changed, 742 insertions(+), 150 deletions(-) create mode 100644 install/bash-preexec.sh create mode 100644 src/ghjk/config.rs diff --git a/deno.lock b/deno.lock index a25e27a..c00cebf 100644 --- a/deno.lock +++ b/deno.lock @@ -100,8 +100,47 @@ "https://deno.land/std@0.116.0/path/win32.ts": "11549e8c6df8307a8efcfa47ad7b2a75da743eac7d4c89c9723a944661c8bd2e", "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", + "https://deno.land/std@0.213.0/assert/_diff.ts": "dcc63d94ca289aec80644030cf88ccbf7acaa6fbd7b0f22add93616b36593840", + "https://deno.land/std@0.213.0/assert/_format.ts": "0ba808961bf678437fb486b56405b6fefad2cf87b5809667c781ddee8c32aff4", "https://deno.land/std@0.213.0/assert/assert.ts": "bec068b2fccdd434c138a555b19a2c2393b71dfaada02b7d568a01541e67cdc5", + "https://deno.land/std@0.213.0/assert/assert_almost_equals.ts": "8b96b7385cc117668b0720115eb6ee73d04c9bcb2f5d2344d674918c9113688f", + "https://deno.land/std@0.213.0/assert/assert_array_includes.ts": "1688d76317fd45b7e93ef9e2765f112fdf2b7c9821016cdfb380b9445374aed1", + "https://deno.land/std@0.213.0/assert/assert_equals.ts": "4497c56fe7d2993b0d447926702802fc0becb44e319079e8eca39b482ee01b4e", + "https://deno.land/std@0.213.0/assert/assert_exists.ts": "24a7bf965e634f909242cd09fbaf38bde6b791128ece08e33ab08586a7cc55c9", + "https://deno.land/std@0.213.0/assert/assert_false.ts": "6f382568e5128c0f855e5f7dbda8624c1ed9af4fcc33ef4a9afeeedcdce99769", + "https://deno.land/std@0.213.0/assert/assert_greater.ts": "4945cf5729f1a38874d7e589e0fe5cc5cd5abe5573ca2ddca9d3791aa891856c", + "https://deno.land/std@0.213.0/assert/assert_greater_or_equal.ts": "573ed8823283b8d94b7443eb69a849a3c369a8eb9666b2d1db50c33763a5d219", + "https://deno.land/std@0.213.0/assert/assert_instance_of.ts": "72dc1faff1e248692d873c89382fa1579dd7b53b56d52f37f9874a75b11ba444", + "https://deno.land/std@0.213.0/assert/assert_is_error.ts": "6596f2b5ba89ba2fe9b074f75e9318cda97a2381e59d476812e30077fbdb6ed2", + "https://deno.land/std@0.213.0/assert/assert_less.ts": "2b4b3fe7910f65f7be52212f19c3977ecb8ba5b2d6d0a296c83cde42920bb005", + "https://deno.land/std@0.213.0/assert/assert_less_or_equal.ts": "b93d212fe669fbde959e35b3437ac9a4468f2e6b77377e7b6ea2cfdd825d38a0", + "https://deno.land/std@0.213.0/assert/assert_match.ts": "ec2d9680ed3e7b9746ec57ec923a17eef6d476202f339ad91d22277d7f1d16e1", + "https://deno.land/std@0.213.0/assert/assert_not_equals.ts": "f3edda73043bc2c9fae6cbfaa957d5c69bbe76f5291a5b0466ed132c8789df4c", + "https://deno.land/std@0.213.0/assert/assert_not_instance_of.ts": "8f720d92d83775c40b2542a8d76c60c2d4aeddaf8713c8d11df8984af2604931", + "https://deno.land/std@0.213.0/assert/assert_not_match.ts": "b4b7c77f146963e2b673c1ce4846473703409eb93f5ab0eb60f6e6f8aeffe39f", + "https://deno.land/std@0.213.0/assert/assert_not_strict_equals.ts": "da0b8ab60a45d5a9371088378e5313f624799470c3b54c76e8b8abeec40a77be", + "https://deno.land/std@0.213.0/assert/assert_object_match.ts": "e85e5eef62a56ce364c3afdd27978ccab979288a3e772e6855c270a7b118fa49", + "https://deno.land/std@0.213.0/assert/assert_rejects.ts": "e9e0c8d9c3e164c7ac962c37b3be50577c5a2010db107ed272c4c1afb1269f54", + "https://deno.land/std@0.213.0/assert/assert_strict_equals.ts": "0425a98f70badccb151644c902384c12771a93e65f8ff610244b8147b03a2366", + "https://deno.land/std@0.213.0/assert/assert_string_includes.ts": "dfb072a890167146f8e5bdd6fde887ce4657098e9f71f12716ef37f35fb6f4a7", + "https://deno.land/std@0.213.0/assert/assert_throws.ts": "edddd86b39606c342164b49ad88dd39a26e72a26655e07545d172f164b617fa7", "https://deno.land/std@0.213.0/assert/assertion_error.ts": "9f689a101ee586c4ce92f52fa7ddd362e86434ffdf1f848e45987dc7689976b8", + "https://deno.land/std@0.213.0/assert/equal.ts": "fae5e8a52a11d3ac694bbe1a53e13a7969e3f60791262312e91a3e741ae519e2", + "https://deno.land/std@0.213.0/assert/fail.ts": "f310e51992bac8e54f5fd8e44d098638434b2edb802383690e0d7a9be1979f1c", + "https://deno.land/std@0.213.0/assert/mod.ts": "325df8c0683ad83a873b9691aa66b812d6275fc9fec0b2d180ac68a2c5efed3b", + "https://deno.land/std@0.213.0/assert/unimplemented.ts": "47ca67d1c6dc53abd0bd729b71a31e0825fc452dbcd4fde4ca06789d5644e7fd", + "https://deno.land/std@0.213.0/assert/unreachable.ts": "38cfecb95d8b06906022d2f9474794fca4161a994f83354fd079cac9032b5145", + "https://deno.land/std@0.213.0/async/_util.ts": "64f8d0da48f908c651736317a36e97890ea9ea22a5e281c8acf9ee6cafbb6de9", + "https://deno.land/std@0.213.0/async/abortable.ts": "87bbc086dfdbb3556fe47d12038dc3919b4f717b3660abb21f800e020c159664", + "https://deno.land/std@0.213.0/async/deadline.ts": "65cf43eb30948f5122fa66a0d6c0fc166af23621632b6e440303efe164e8a0db", + "https://deno.land/std@0.213.0/async/debounce.ts": "214cee25fb32ee8df89775f0c81902aa52f2a6c1fa13afa3fddbb6ddccc1446d", + "https://deno.land/std@0.213.0/async/delay.ts": "8e1d18fe8b28ff95885e2bc54eccec1713f57f756053576d8228e6ca110793ad", + "https://deno.land/std@0.213.0/async/mod.ts": "02ba6a7d065481b6318d0783ad7243426e4f1bc4cdee0d1b6460bf73e9eab3e3", + "https://deno.land/std@0.213.0/async/mux_async_iterator.ts": "33aa184f27fd2be1467dab3785dfdf525c8b8acd150a049331f0fdf927a17dda", + "https://deno.land/std@0.213.0/async/pool.ts": "2b972e3643444b73f6a8bcdd19799a2d0821b28a45fbe47fd333223eb84327f0", + "https://deno.land/std@0.213.0/async/retry.ts": "718335f89d1fbd2156109b05d2399a2b47c848a5a8f7237640538902526b38f7", + "https://deno.land/std@0.213.0/async/tee.ts": "34373c58950b7ac5950632dc8c9908076abeefcc9032d6299fff92194c284fbd", "https://deno.land/std@0.213.0/bytes/concat.ts": "9cac3b4376afbef98ff03588eb3cf948e0d1eb6c27cfe81a7651ab6dd3adc54a", "https://deno.land/std@0.213.0/bytes/copy.ts": "f29c03168853720dfe82eaa57793d0b9e3543ebfe5306684182f0f1e3bfd422a", "https://deno.land/std@0.213.0/fmt/colors.ts": "aeaee795471b56fc62a3cb2e174ed33e91551b535f44677f6320336aabb54fbb", @@ -389,6 +428,7 @@ "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/jszip@0.11.0/types.ts": "1528d1279fbb64dd118c371331c641a3a5eff2b594336fb38a7659cf4c53b2d1", "https://esm.sh/jszip@3.7.1": "f3872a819b015715edb05f81d973b5cd05d3d213d8eb28293ca5471fe7a71773", "https://esm.sh/v135/jszip@3.7.1/denonext/jszip.mjs": "d31d7f9e0de9c6db3c07ca93f7301b756273d4dccb41b600461978fc313504c9" } diff --git a/ghjk.ts b/ghjk.ts index 343de45..de6ff25 100644 --- a/ghjk.ts +++ b/ghjk.ts @@ -15,7 +15,7 @@ config({ }); env("main").vars({ - RUST_LOG: "info,deno=info,denort=trace,swc_ecma_transforms_base=info", + RUST_LOG: "info,deno=info,denort=trace,swc_ecma_transforms_base=info,swc_common=info", }); env("_rust") @@ -175,5 +175,5 @@ task( }, ); }, - { inherits:false } + { inherits: false }, ); diff --git a/install/bash-preexec.sh b/install/bash-preexec.sh new file mode 100644 index 0000000..29c3f06 --- /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/hook.fish b/install/hook.fish index 916890c..0d0d714 100644 --- a/install/hook.fish +++ b/install/hook.fish @@ -109,6 +109,7 @@ function __ghjk_preexec --on-event fish_preexec # activate script has reloaded else if set --query GHJK_LAST_ENV_DIR; + and test -e $next_env_dir/activate.fish; and test (__ghjk_get_mtime_ts $GHJK_LAST_ENV_DIR/activate.fish) -gt $GHJK_LAST_ENV_DIR_MTIME; ghjk_hook end diff --git a/install/hook.sh b/install/hook.sh index 2e697b9..2038bde 100644 --- a/install/hook.sh +++ b/install/hook.sh @@ -109,7 +109,7 @@ precmd() { 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_hook diff --git a/src/deno_systems/bindings.ts b/src/deno_systems/bindings.ts index f53cbb3..84e3021 100644 --- a/src/deno_systems/bindings.ts +++ b/src/deno_systems/bindings.ts @@ -24,10 +24,13 @@ setInterval(() => {/* beat */}, 1000); const prepareArgs = zod.object({ uri: zod.string(), - gcx: zod.object({ - ghjkfile_path: zod.string().optional(), - ghjk_dir_path: zod.string(), - share_dir_path: 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(), }), }); @@ -36,10 +39,10 @@ await prepareSystems(args); async function prepareSystems(args: zod.infer) { const gcx = { - ghjkDir: $.path(args.gcx.ghjk_dir_path), - ghjkShareDir: $.path(args.gcx.share_dir_path), - ghjkfilePath: args.gcx.ghjkfile_path - ? $.path(args.gcx.ghjkfile_path) + ghjkDir: $.path(args.config.ghjkdir), + ghjkShareDir: $.path(args.config.data_dir), + ghjkfilePath: args.config.ghjkfile + ? $.path(args.config.ghjkfile) : undefined, blackboard: new Map(), } satisfies GhjkCtx; diff --git a/src/ghjk/cli.rs b/src/ghjk/cli.rs index 6d8af66..3be391f 100644 --- a/src/ghjk/cli.rs +++ b/src/ghjk/cli.rs @@ -2,110 +2,30 @@ 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, utils}; - -#[derive(Debug)] -pub struct Config { - pub ghjkfile_path: Option, - pub ghjkdir_path: Option, - pub share_dir_path: PathBuf, -} +use crate::{host, systems}; const DENO_UNSTABLE_FLAGS: &[&str] = &["worker-options", "kv"]; pub async fn cli() -> Res { let cwd = std::env::current_dir()?; - let (config, deno_lockfile_path) = { - let ghjk_dir_path = match std::env::var("GHJK_DIR") { - Ok(path) => Some(PathBuf::from(path)), - Err(std::env::VarError::NotUnicode(os_str)) => Some(PathBuf::from(os_str)), - Err(std::env::VarError::NotPresent) => { - utils::find_entry_recursive(&cwd, ".ghjk").await? - } - }; - - let ghjk_dir_path = if let Some(path) = ghjk_dir_path { - Some(tokio::fs::canonicalize(path).await?) - } else { - None - }; - - let ghjkfile_path = match &ghjk_dir_path { - Some(ghjkfile_path) => { - utils::find_entry_recursive( - ghjkfile_path - .parent() - .expect_or_log("invalid GHJK_DIR path"), - "ghjk.ts", - ) - .await? - } - None => utils::find_entry_recursive(&cwd, "ghjk.ts").await?, - }; - - let (ghjkfile_path, ghjk_dir_path) = if let Some(path) = ghjkfile_path { - let file_path = tokio::fs::canonicalize(path).await?; - // if ghjkfile var is set, set the GHJK_DIR overriding - // any set by the user - let dir_path = file_path.parent().unwrap().join(".ghjk"); - (Some(file_path), Some(dir_path)) - } else { - (None, ghjk_dir_path) - }; - - if ghjk_dir_path.is_none() && ghjkfile_path.is_none() { - warn!( - "ghjk could not find any ghjkfiles or ghjkdirs, try creating a `ghjk.ts` script.", - ); - } - - let share_dir_path = match std::env::var("GHJK_SHARE_DIR") { - Ok(path) => PathBuf::from(path), - Err(std::env::VarError::NotUnicode(os_str)) => PathBuf::from(os_str), - Err(std::env::VarError::NotPresent) => directories::BaseDirs::new() - .expect_or_log("unable to resolve home dir") - .data_local_dir() - .join("ghjk"), - }; - - let deno_lockfile_path = match std::env::var("GHJK_DENO_LOCKFILE") { - Ok(str) if str == "off" => None, - Ok(path) => Some(PathBuf::from(path)), - Err(std::env::VarError::NotUnicode(os_str)) => Some(PathBuf::from(os_str)), - Err(std::env::VarError::NotPresent) => match &ghjk_dir_path { - Some(path) => Some(path.join("deno.lock")), - None => None, - }, - }; - - ( - Config { - ghjkfile_path, - ghjkdir_path: ghjk_dir_path, - share_dir_path, - }, - deno_lockfile_path, - ) - }; + let config = Config::source().await?; let Some(quick_err) = try_quick_cli(&config).await? else { return Ok(ExitCode::SUCCESS); }; - let Some(ghjk_dir_path) = config.ghjkdir_path.clone() else { + let Some(ghjkdir_path) = config.ghjkdir.clone() else { quick_err.exit(); }; - // TODO: create ghjk_dir_path if it doens't exist - // TODO: create .gitignore file as well - - let deno_cx = denort::worker( + let deno_cx = { // TODO: DENO_FLAGS param simlar to V8_FLAGS - denort::deno::args::Flags { + let flags = denort::deno::args::Flags { unstable_config: denort::deno::args::UnstableConfig { features: DENO_UNSTABLE_FLAGS .iter() @@ -114,38 +34,34 @@ pub async fn cli() -> Res { .collect(), ..default() }, - no_lock: deno_lockfile_path.is_none(), - lock: deno_lockfile_path.map(|path| path.to_string_lossy().into()), + no_lock: config.deno_lockfile.is_none(), + lock: config + .deno_lockfile + .as_ref() + .map(|path| path.to_string_lossy().into()), ..default() - }, - Some(Arc::new(Vec::new)), - ) - .await?; + }; + denort::worker(flags, Some(Arc::new(Vec::new))).await? + }; let gcx = GhjkCtx { - ghjk_dir_path, - ghjkfile_path: config.ghjkfile_path.clone(), - share_dir_path: config.share_dir_path.clone(), - repo_root: url::Url::from_file_path(&cwd) - .expect_or_log("cwd error") - // repo root url must end in slash due to - // how Url::join works - .join(&format!("{}/", cwd.file_name().unwrap().to_string_lossy())) - .wrap_err("repo url error")?, + config, deno: deno_cx.clone(), }; let gcx = Arc::new(gcx); let systems_deno = systems::deno::systems_from_deno( &gcx, - &gcx.repo_root + &gcx.config + .repo_root .join("src/deno_systems/mod.ts") .wrap_err("repo url error")?, + &ghjkdir_path, ) .await?; let hcx = host::HostCtx::new( - gcx, + gcx.clone(), host::Config { re_resolve: false, locked: false, @@ -158,7 +74,7 @@ pub async fn cli() -> Res { let hcx = Arc::new(hcx); - let Some(mut systems) = host::systems_from_ghjkfile(hcx).await? else { + let Some(mut systems) = host::systems_from_ghjkfile(hcx, &ghjkdir_path).await? else { warn!("no ghjkfile found"); quick_err.exit() }; @@ -196,7 +112,7 @@ pub async fn cli() -> Res { match QuickComands::from_arg_matches(&matches) { Ok(QuickComands::Print { commands }) => { - _ = commands.action(&config, Some(&systems.config))?; + _ = commands.action(&gcx.config, Some(&systems.config))?; return Ok(ExitCode::SUCCESS); } Ok(QuickComands::Deno { .. }) => { @@ -309,8 +225,8 @@ enum QuickComands { #[derive(clap::Subcommand, Debug)] enum PrintCommands { - /// Print the path where ghjk is installed in. - ShareDirPath, + /// 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. @@ -333,13 +249,13 @@ impl PrintCommands { serialized_config: Option<&host::SerializedConfig>, ) -> Res { Ok(match self { - PrintCommands::ShareDirPath => { - println!("{}", cli_config.share_dir_path.display()); + PrintCommands::DataDirPath => { + println!("{}", cli_config.data_dir.display()); true } // TODO: rename GHJK_DIR to GHJKDIR PrintCommands::GhjkdirPath => { - if let Some(path) = &cli_config.ghjkdir_path { + if let Some(path) = &cli_config.ghjkdir { // TODO: graceful termination on SIGPIPE println!("{}", path.display()); true @@ -348,7 +264,7 @@ impl PrintCommands { } } PrintCommands::GhjkfilePath => { - if let Some(path) = &cli_config.ghjkdir_path { + if let Some(path) = &cli_config.ghjkdir { println!("{}", path.display()); true } else { @@ -457,9 +373,7 @@ async fn action_for_match( /// 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 Some(first) = argv.get(0) else { - return None; - }; + let first = argv.first()?; if first != "deno" { return None; } diff --git a/src/ghjk/config.rs b/src/ghjk/config.rs new file mode 100644 index 0000000..c7f39e5 --- /dev/null +++ b/src/ghjk/config.rs @@ -0,0 +1,272 @@ +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").await? { + 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").await? { + 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?; + 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") + // repo root url must end in slash due to + // how Url::join works + .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") + } + }, + }; + // we use builtin config-rs File implementation + // which relies on sync std + let config = tokio::task::spawn_blocking(move || { + { + let file_path = xdg_dirs.config_dir().join("conf.json"); + config + .source_global_config(&file_path) + .wrap_err_with(|| format!("error sourcing global config from {file_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")?; + + 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::fs::canonicalize(&path) + .wrap_err_with(|| format!("error canonicalizing path at {path:?}"))?; + Ok(path) +} + +async 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(tokio::fs::canonicalize(&path).await.wrap_err_with( + || format!("error canonicalizing path {path:?} from env ${env_name}"), + )?)) + } else { + Ok(None) + } +} diff --git a/src/ghjk/host.rs b/src/ghjk/host.rs index 73776c5..2f9e775 100644 --- a/src/ghjk/host.rs +++ b/src/ghjk/host.rs @@ -46,10 +46,13 @@ impl HostCtx { } #[tracing::instrument(skip(hcx))] -pub async fn systems_from_ghjkfile(hcx: Arc) -> Res> { +pub async fn systems_from_ghjkfile( + hcx: Arc, + ghjkdir_path: &Path, +) -> Res> { let (hashfile_path, lockfile_path) = ( - hcx.gcx.ghjk_dir_path.join("hash.json"), - hcx.gcx.ghjk_dir_path.join("lock.json"), + ghjkdir_path.join("hash.json"), + ghjkdir_path.join("lock.json"), ); let (hash_obj, lock_obj) = ( @@ -73,7 +76,7 @@ pub async fn systems_from_ghjkfile(hcx: Arc) -> Res) -> Res Res { let main_module = hcx .gcx + .config .repo_root .join("files/deno/bindings.ts") .wrap_err("repo url error")?; diff --git a/src/ghjk/main.rs b/src/ghjk/main.rs index 2f99b9e..abbdb26 100644 --- a/src/ghjk/main.rs +++ b/src/ghjk/main.rs @@ -70,8 +70,5 @@ shadow!(shadow); #[derive(Debug)] pub struct GhjkCtx { deno: denort::DenoWorkerHandle, - repo_root: url::Url, - ghjkfile_path: Option, - ghjk_dir_path: PathBuf, - share_dir_path: PathBuf, + config: config::Config, } diff --git a/src/ghjk/systems/deno.rs b/src/ghjk/systems/deno.rs index 63b1ba5..738bfaa 100644 --- a/src/ghjk/systems/deno.rs +++ b/src/ghjk/systems/deno.rs @@ -35,8 +35,10 @@ impl DenoSystemsContext { pub async fn systems_from_deno( gcx: &GhjkCtx, source_uri: &url::Url, + ghjkdir_path: &Path, ) -> Res> { let main_module = gcx + .config .repo_root .join("src/deno_systems/bindings.ts") .wrap_err("repo url error")?; @@ -46,32 +48,38 @@ pub async fn systems_from_deno( let bb = ext_conf.blackboard.clone(); bb.insert("args".into(), { #[derive(Serialize)] - struct GhjkCtxBean<'a> { - ghjkfile_path: Option<&'a Path>, - ghjk_dir_path: &'a Path, - share_dir_path: &'a Path, + 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, - gcx: GhjkCtxBean<'a>, + config: ConfigRef<'a>, } - let GhjkCtx { - deno, + let crate::config::Config { repo_root, - ghjkfile_path, - ghjk_dir_path, - share_dir_path, - } = gcx; - _ = (deno, repo_root); + ghjkdir: _, + data_dir, + deno_lockfile, + ghjkfile, + deno_dir, + } = &gcx.config; serde_json::json!(BindingArgs { uri: source_uri.clone(), - gcx: GhjkCtxBean { - ghjkfile_path: ghjkfile_path.as_ref().map(|path| path.as_path()), - ghjk_dir_path, - share_dir_path, + 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 }, }) }); From 3779222a540bdeb88bb142ae17e1e6032bc082db Mon Sep 17 00:00:00 2001 From: Yohe-Am <56622350+Yohe-Am@users.noreply.github.com> Date: Tue, 10 Dec 2024 13:11:03 +0300 Subject: [PATCH 05/13] wip: fix test harness --- deno.lock | 10 ++ ghjk.ts | 3 +- install.sh | 180 +++++++++++++++++++++++++++++++---- install.ts | 16 +--- install/ghjk.sh | 55 ----------- install/mod.ts | 83 ++-------------- install/utils.ts | 19 +--- modules/envs/posix.ts | 7 +- scripts/dev.ts | 24 ++--- src/ghjk/config.rs | 13 ++- src/ghjk/systems/deno/cli.rs | 4 +- tests/utils.ts | 33 +++---- 12 files changed, 228 insertions(+), 219 deletions(-) delete mode 100644 install/ghjk.sh diff --git a/deno.lock b/deno.lock index c00cebf..56220f3 100644 --- a/deno.lock +++ b/deno.lock @@ -13,6 +13,7 @@ "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" @@ -72,9 +73,18 @@ "@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==" + }, "zod-validation-error@3.4.0_zod@3.23.8": { "integrity": "sha512-ZOPR9SVY6Pb2qqO5XHt+MkkTRxGXb4EVtnjc9JpXUOtUB1T9Ru7mZOT361AN3MsetVe7R0a1KZshJDZdgp9miQ==", "dependencies": [ diff --git a/ghjk.ts b/ghjk.ts index de6ff25..c718be0 100644 --- a/ghjk.ts +++ b/ghjk.ts @@ -15,7 +15,8 @@ config({ }); env("main").vars({ - RUST_LOG: "info,deno=info,denort=trace,swc_ecma_transforms_base=info,swc_common=info", + RUST_LOG: + "info,deno=info,denort=trace,swc_ecma_transforms_base=info,swc_common=info", }); env("_rust") diff --git a/install.sh b/install.sh index daf29c0..0d7a076 100755 --- a/install.sh +++ b/install.sh @@ -2,33 +2,173 @@ set -e -u -GHJK_VERSION="${GHJK_VERSION:-v0.3.0}" -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:-v2.1.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 +21,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/ghjk.sh b/install/ghjk.sh deleted file mode 100644 index 49d0d83..0000000 --- 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 ultimately 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/mod.ts b/install/mod.ts index d42a52b..7297518 100644 --- a/install/mod.ts +++ b/install/mod.ts @@ -10,14 +10,6 @@ import type { Path } from "../utils/mod.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 @@ -104,21 +96,17 @@ async function filterAddContent( interface InstallArgs { homeDir: string; - ghjkShareDir: string; + ghjkDataDir: string; ghjkConfigDir: 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 cache dir to use by the ghjk deno installation. - */ - ghjkDenoCacheDir?: string; } export const defaultInstallArgs: InstallArgs = { - ghjkShareDir: $.path(dirs().shareDir).resolve("ghjk").toString(), + ghjkDataDir: $.path(dirs().shareDir).resolve("ghjk").toString(), homeDir: dirs().homeDir, shellsToHook: [], shellHookMarker: "ghjk-hook-default", @@ -139,14 +127,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_SHARE_DIR__/g, ghjkDataDir.toString()]], ); for (const shell of args.shellsToHook ?? Object.keys(shellConfig)) { const { homeDir } = args; @@ -162,7 +150,7 @@ export async function install( continue; } logger.info("installing hook", { - ghjkShareDir, + ghjkDataDir, shell, marker: args.shellHookMarker, rcPath, @@ -170,60 +158,7 @@ export async function install( await filterAddContent( rcPath, new RegExp(args.shellHookMarker, "g"), - `. ${ghjkShareDir}/env.${shell} # ${args.shellHookMarker}`, - ); - } - - if (!args.skipExecInstall) { - const installDir = await $.path(args.ghjkExecInstallDir).ensureDir(); - switch (Deno.build.os) { - case "linux": - case "freebsd": - case "solaris": - case "illumos": - case "darwin": { - const exePath = installDir.resolve(`ghjk`); - logger.debug("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.warn( - "make sure to add the following to your $PATH to access the ghjk CLI", - ); - logger.warn( - installDir.toString(), + `. ${ghjkDataDir}/env.${shell} # ${args.shellHookMarker}`, ); } - logger.info("install success"); } diff --git a/install/utils.ts b/install/utils.ts index 1f5bb9b..f89cd2b 100644 --- a/install/utils.ts +++ b/install/utils.ts @@ -1,24 +1,17 @@ //! 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. */ 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()} "$@" }`; } @@ -27,18 +20,10 @@ export function ghjk_sh( */ 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/modules/envs/posix.ts b/modules/envs/posix.ts index 73f479e..e9d0f21 100644 --- a/modules/envs/posix.ts +++ b/modules/envs/posix.ts @@ -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 @@ -309,7 +306,7 @@ async function writeActivators( // 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), + ghjk_sh(gcx, ghjkShimName), ``, `# only run the hooks in interactive mode`, `case "$-" in`, @@ -377,7 +374,7 @@ async function writeActivators( ``, `# hooks that want to invoke ghjk are made to rely`, `# on this shim to improve latency`, - ghjk_fish(gcx, denoDir, ghjkShimName), + ghjk_fish(gcx, ghjkShimName), ``, `# only run the hooks in interactive mode`, `if status is-interactive;`, diff --git a/scripts/dev.ts b/scripts/dev.ts index 45c2033..2fdad21 100755 --- a/scripts/dev.ts +++ b/scripts/dev.ts @@ -14,28 +14,28 @@ const devDir = $.path( // }), ).join("../.dev"); -const ghjkShareDir = await devDir.join("ghjk").ensureDir(); +const ghjkDataDir = 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")}`, + BASH_ENV: `${ghjkDataDir.toString()}/env.bash`, + ZDOTDIR: ghjkDataDir.toString(), + GHJK_SHARE_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, - 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: [], }); @@ -56,7 +56,7 @@ if (Deno.args.length) { } else if (Deno.args[0] == "fish" && Deno.args.length == 1) { // cmd = $`fish --no-config --init-command 'source ${ cmd = $`fish --init-command 'source ${ - ghjkShareDir.join("env.fish").toString() + ghjkDataDir.join("env.fish").toString() }'`; } else { cmd = $`${Deno.args}`; diff --git a/src/ghjk/config.rs b/src/ghjk/config.rs index c7f39e5..fbf0a10 100644 --- a/src/ghjk/config.rs +++ b/src/ghjk/config.rs @@ -101,14 +101,21 @@ impl Config { } }, }; + + let global_config_path = match path_from_env(&cwd, "GHJK_CONFIG_DIR").await? { + 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 || { { - let file_path = xdg_dirs.config_dir().join("conf.json"); config - .source_global_config(&file_path) - .wrap_err_with(|| format!("error sourcing global config from {file_path:?}"))?; + .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 { diff --git a/src/ghjk/systems/deno/cli.rs b/src/ghjk/systems/deno/cli.rs index 057d8b8..221b4b9 100644 --- a/src/ghjk/systems/deno/cli.rs +++ b/src/ghjk/systems/deno/cli.rs @@ -85,9 +85,9 @@ impl CliCommandDesc { deno_cb_action(matches, scx.clone(), cb_key, flag_ids).boxed() })) } else { - if sub_commands.is_empty() { + /* if sub_commands.is_empty() { error!("a system command has no action or subcommands attached"); - } + } */ None }; diff --git a/tests/utils.ts b/tests/utils.ts index e471437..b468677 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -117,7 +117,7 @@ export async function localE2eTest(testCase: E2eTestCase) { prefix: "ghjk_le2e_", }), ); - const ghjkShareDir = await tmpDir.join("ghjk").ensureDir(); + const ghjkDataDir = await tmpDir.join("ghjk").ensureDir(); await tmpDir.join("ghjk.ts").writeText( tsGhjkfileStr.replaceAll( @@ -125,41 +125,42 @@ export async function localE2eTest(testCase: E2eTestCase) { std_url.dirname(import.meta.resolve("../mod.ts")).href, ), ); + + const ghjkExePath = $.path(import.meta.resolve("../target/debug/ghjk")); + const env: Record = { GHJK_AUTO_HOOK: "true", - BASH_ENV: `${ghjkShareDir.toString()}/env.bash`, - ZDOTDIR: ghjkShareDir.toString(), - GHJK_SHARE_DIR: ghjkShareDir.toString(), - PATH: `${ghjkShareDir.toString()}:${Deno.env.get("PATH")}`, + BASH_ENV: `${ghjkDataDir.toString()}/env.bash`, + ZDOTDIR: ghjkDataDir.toString(), + GHJK_DATA_DIR: ghjkDataDir.toString(), + PATH: `${ghjkExePath.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("HOME")!).join(".cache", "deno").toString(), ...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(), - ghjkExecDenoExec: "deno", + ghjkDataDir: ghjkDataDir.toString(), // don't modify system shell configs shellsToHook: [], }); - await $`${ghjkShareDir.join("ghjk").toString()} print config` + await $`${ghjkExePath} print config` .cwd(tmpDir.toString()) .clearEnv() .env(env); - await $`${ghjkShareDir.join("ghjk").toString()} envs cook` + await $`${ghjkExePath} 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), ])); @@ -168,7 +169,7 @@ export async function localE2eTest(testCase: E2eTestCase) { 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(); } From 096d02d5228dd23ff55cce4d211020746acb33f9 Mon Sep 17 00:00:00 2001 From: Yohe-Am <56622350+Yohe-Am@users.noreply.github.com> Date: Sat, 21 Dec 2024 15:41:10 +0100 Subject: [PATCH 06/13] fix: fix deadlock on errors --- .cargo/config.toml | 7 + .ghjk/lock.json | 69 ++++- Cargo.lock | 81 +++++ deno.jsonc | 2 +- ghjk.ts | 5 +- install.ts | 6 + modules/ports/worker.ts | 2 + src/denort/lib.rs | 605 +++----------------------------------- src/denort/promises.rs | 21 +- src/denort/unsync.rs | 280 ++++++++++++++++++ src/denort/worker.rs | 562 +++++++++++++++++++++++++++++++++++ src/ghjk/Cargo.toml | 5 +- src/ghjk/cli.rs | 8 +- src/ghjk/config.rs | 4 +- src/ghjk/ext.rs | 7 +- src/ghjk/ext/callbacks.rs | 114 ++++--- src/ghjk/host.rs | 78 ++++- src/ghjk/host/hashfile.rs | 29 +- src/ghjk/log.rs | 16 +- src/ghjk/main.rs | 2 +- src/ghjk/systems/deno.rs | 12 +- src/ghjk/utils.rs | 18 +- tests/envs.ts | 1 + tests/utils.ts | 4 +- 24 files changed, 1254 insertions(+), 684 deletions(-) create mode 100644 src/denort/unsync.rs create mode 100644 src/denort/worker.rs diff --git a/.cargo/config.toml b/.cargo/config.toml index 6c8d827..05dde38 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,3 +1,10 @@ [alias] xtask = "run --package xtask --" x = "run --package xtask --" + +[target.x86_64-unknown-linux-gnu] +rustflags = [ + # for use with tokio-rs/console + "--cfg", + "tokio_unstable" +] diff --git a/.ghjk/lock.json b/.ghjk/lock.json index 5da7196..ad0600a 100644 --- a/.ghjk/lock.json +++ b/.ghjk/lock.json @@ -1,7 +1,6 @@ { "version": "0", - "platform": "x86_64-linux", - "moduleEntries": { + "sys_entries": { "ports": { "version": "0", "configResolutions": { @@ -287,6 +286,7 @@ }, "ghjkEnvProvInstSet___dev": { "installs": [ + "bciqlfx3mm5hi37g75snjknph6fkniixjhnvyyfxeua7f5z4h7nnqtna", "bciqlmoqot4jk2lb2b34pldr5iiwsfm3biuipzesjkkwmc2n2o6nlw4q", "bciqikjfnbntvagpghawbzlfp2es6lnqzhba3qx5de7tdrmvhuzhsjqa", "bciqfrfun7z7soj7yxzziyvmt2jnebqvneeoozk5vynmg5pa6wqynhvi", @@ -312,7 +312,7 @@ "lock-sed": { "ty": "denoFile@v1", "key": "lock-sed", - "envKey": "bciqcjjccn4eivzzybioty5p5tde6gnafea43rypzxci54tqjfglxyyy" + "envKey": "bciqbs6giotedkicnvrztzwovfr4siq2phoa63wngljmzna6aa4kyciy" }, "cache-v8": { "ty": "denoFile@v1", @@ -339,13 +339,13 @@ } ] }, - "bciqkjh3l5pvnydjxc3gp6autcaurxvw2euj7uz472qureg3p4y5nfuq": { + "bciqonpyvifzte5gf6tl7gtk3ep5q3vst2gqncuznf3kav4mzbuvnpai": { "desc": "the default default environment.", "provides": [ { "ty": "posix.envVar", "key": "RUST_LOG", - "val": "info,deno=info,denort=trace,swc_ecma_transforms_base=info" + "val": "info,deno=info,denort=trace,swc_ecma_transforms_base=info,swc_common=info,h2=info,rustls=info,mio=info,hyper_util=info" }, { "ty": "ghjk.ports.InstallSetRef", @@ -353,12 +353,12 @@ } ] }, - "bciqcjjccn4eivzzybioty5p5tde6gnafea43rypzxci54tqjfglxyyy": { + "bciqbs6giotedkicnvrztzwovfr4siq2phoa63wngljmzna6aa4kyciy": { "provides": [ { "ty": "posix.envVar", "key": "RUST_LOG", - "val": "info,deno=info,denort=trace,swc_ecma_transforms_base=info" + "val": "info,deno=info,denort=trace,swc_ecma_transforms_base=info,swc_common=info,h2=info,rustls=info,mio=info,hyper_util=info" }, { "ty": "ghjk.ports.InstallSetRef", @@ -366,12 +366,12 @@ } ] }, - "bciqothoegu7lnencjdk6pjtassehqlzaldan6l67lmtd2slhmvnq5la": { + "bciqm4lt7lvjdt3qzudw24qe4brezcej3ilxxhbmgfo2gdbfmh4j3a7i": { "provides": [ { "ty": "posix.envVar", "key": "RUST_LOG", - "val": "info,deno=info,denort=trace,swc_ecma_transforms_base=info" + "val": "info,deno=info,denort=trace,swc_ecma_transforms_base=info,swc_common=info,h2=info,rustls=info,mio=info,hyper_util=info" }, { "ty": "ghjk.ports.InstallSetRef", @@ -379,17 +379,17 @@ } ] }, - "bciqdlbved4xvo27dss37motxje63ai3mwc4g5otjre5heqto2g7zbhi": { + "bciqdngvsrwedhravpw6h4lzku6f52ljmexs6sqrtowntcqpguibfgti": { "provides": [ { "ty": "posix.envVar", "key": "RUST_LOG", - "val": "info,deno=info,denort=trace,swc_ecma_transforms_base=info" + "val": "info,deno=info,denort=trace,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": "/home/asdf/repos/ecma/ghjk/.dev/rusty_v8" + "val": "/home/yohe/ghjk/.dev/rusty_v8" }, { "ty": "ghjk.ports.InstallSetRef", @@ -400,9 +400,9 @@ }, "defaultEnv": "dev", "envsNamed": { - "main": "bciqkjh3l5pvnydjxc3gp6autcaurxvw2euj7uz472qureg3p4y5nfuq", - "_rust": "bciqothoegu7lnencjdk6pjtassehqlzaldan6l67lmtd2slhmvnq5la", - "dev": "bciqdlbved4xvo27dss37motxje63ai3mwc4g5otjre5heqto2g7zbhi" + "main": "bciqonpyvifzte5gf6tl7gtk3ep5q3vst2gqncuznf3kav4mzbuvnpai", + "_rust": "bciqm4lt7lvjdt3qzudw24qe4brezcej3ilxxhbmgfo2gdbfmh4j3a7i", + "dev": "bciqdngvsrwedhravpw6h4lzku6f52ljmexs6sqrtowntcqpguibfgti" } } } @@ -904,6 +904,43 @@ "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": "rust_rustup" + } + ], + "moduleSpecifier": "file:///ports/cargobi.ts" + }, + "crateName": "tokio-console" + }, "bciqlmoqot4jk2lb2b34pldr5iiwsfm3biuipzesjkkwmc2n2o6nlw4q": { "version": "v2.4.0", "port": { @@ -926,4 +963,4 @@ "bciqeie3punk3gz4kcfdk2fxx5bsj5fh3j7bb7z36qmimayhwdsvp7cq": {} } } -} +} \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index a8c1ed4..997711b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -925,6 +925,58 @@ dependencies = [ "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" @@ -2593,6 +2645,19 @@ 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" @@ -2971,6 +3036,12 @@ dependencies = [ "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" @@ -3542,10 +3613,13 @@ dependencies = [ "clap_complete", "color-eyre", "config", + "console", + "console-subscriber", "dashmap", "data-encoding", "deno_core", "denort", + "dialoguer", "directories", "educe", "futures", @@ -6907,6 +6981,12 @@ 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" @@ -7895,6 +7975,7 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", + "tracing", "windows-sys 0.48.0", ] diff --git a/deno.jsonc b/deno.jsonc index 0bcb7ce..6ae9b9b 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -1,6 +1,6 @@ { "tasks": { - "test": "cargo build -p ghjk && deno test --parallel --unstable-worker-options --unstable-kv -A tests/*", + "test": "cargo build -p ghjk && deno test --unstable-worker-options --unstable-kv -A tests/*", "self": "deno run -A --unstable-kv --unstable-worker-options main.ts ", "cache": "deno cache deps/*", "check": "deno run -A ./scripts/check.ts", diff --git a/ghjk.ts b/ghjk.ts index c718be0..6c209e7 100644 --- a/ghjk.ts +++ b/ghjk.ts @@ -16,7 +16,7 @@ config({ env("main").vars({ RUST_LOG: - "info,deno=info,denort=trace,swc_ecma_transforms_base=info,swc_common=info", + "info,deno=info,denort=trace,swc_ecma_transforms_base=info,swc_common=info,h2=info,rustls=info,mio=info,hyper_util=info", }); env("_rust") @@ -35,6 +35,7 @@ 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, @@ -65,7 +66,7 @@ task( "cache-v8", { desc: "Install the V8 builds to a local cache.", - inherit: "_rust", + inherit: false, fn: async ($) => { const tmpDirPath = await Deno.makeTempDir({}); const v8Versions = [ diff --git a/install.ts b/install.ts index c87226c..b494029 100755 --- a/install.ts +++ b/install.ts @@ -5,6 +5,12 @@ import "./setup_logger.ts"; import { defaultInstallArgs, install } from "./install/mod.ts"; +// import the main entry points so that they get cached into the deno +// store during install +import "./modules/std.ts"; +import "./port.ts"; +import "./ports/mod.ts"; + if (import.meta.main) { const shellsToHook = Deno.env.get("GHJK_INSTALL_HOOK_SHELLS") ?.split(",") diff --git a/modules/ports/worker.ts b/modules/ports/worker.ts index 383673c..97bf2d5 100644 --- a/modules/ports/worker.ts +++ b/modules/ports/worker.ts @@ -164,6 +164,8 @@ 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 diff --git a/src/denort/lib.rs b/src/denort/lib.rs index bfacbb7..22c7a94 100644 --- a/src/denort/lib.rs +++ b/src/denort/lib.rs @@ -3,6 +3,8 @@ pub use deno; pub mod promises; +pub mod unsync; +pub mod worker; #[allow(unused)] mod interlude { @@ -21,13 +23,10 @@ mod interlude { } 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, - }, - *, +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] @@ -49,536 +48,6 @@ pub fn init() { }; } -// thread tag used for basic sanity checks -pub const WORKER_THREAD_NAME: &str = "denort-worker-thread"; - -/// This starts a new thread and uses it to run all the tasks -/// that'll need to touch deno internals. Deno is single threaded. -/// -/// Returned handles 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::unbounded_channel::(); - - let (term_signal_tx, mut term_signal_rx) = tokio::sync::watch::channel(false); - - let join_handle = deno_core::unsync::spawn( - async move { - trace!("starting deno worker"); - loop { - let msg = tokio::select! { - Some(msg) = msg_rx.recv() => { - msg - } - _ = term_signal_rx.changed() => break, - else => break - }; - trace!(?msg, "deno worker msg"); - match msg { - DenoWorkerMsg::PrepareModule { - response_channel, - inner, - } => { - response_channel - .send(module_worker(&cx, term_signal_rx.clone(), inner).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: term_signal_tx, - join_handle, - }) -} - -type TermSignal = tokio::sync::watch::Receiver; - -async fn module_worker( - cx: &WorkerContext, - global_term_signal: TermSignal, - msg: PrepareModuleMsg, -) -> 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); - deno_core::unsync::spawn( - 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 - .map_err(|err| ferr!(Box::new(err))), - ) - .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(|err| ferr!(Box::new(err))), - ) - .expect_or_log("channel error"), - ModuleWorkerReq::Execute { response_channel } => response_channel - .send( - module_cx - .execute_main_module() - .await - .map_err(|err| ferr!(Box::new(err))), - ) - .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(|err| ferr!(Box::new(err)))? - .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(|err| ferr!(Box::new(err)))? - .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(|err| ferr!(Box::new(err)))?; - let maybe_coverage_collector = worker - .maybe_setup_coverage_collector() - .await - .map_err(|err| ferr!(Box::new(err)))?; - - // 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::UnboundedSender, - term_signal: tokio::sync::watch::Sender, - #[educe(Debug(ignore))] - join_handle: Arc>>>, -} - -impl DenoWorkerHandle { - pub async fn terminate(self) -> Res<()> { - self.term_signal.send(true)?; - 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(()); - }; - 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, - }, - }) - .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() - .walk( - [&self.main_module].into_iter(), - deno::deno_graph::WalkOptions { - kind: deno::deno_graph::GraphKind::CodeOnly, - check_js: false, - follow_dynamic: true, - prefer_fast_check_graph: false, - }, - ) - .map(|(url, _)| url.clone()) - .collect() - } - - async fn run(&mut self, global_term_signal: TermSignal) -> anyhow::Result { - debug!("main_module {}", self.main_module); - self.execute_main_module().await?; - - let (_local_signal_tx, local_signal_rx) = tokio::sync::watch::channel(false); - self.drive_till_exit(global_term_signal, local_signal_rx) - .await - } - - 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(false).boxed_local(); - - tokio::select! { - _ = global_term_signal.changed() => { - trace!("global term signal lit, shutting down event loop"); - break - }, - _ = term_signal.changed() => { - trace!("worker term signal lit, shutting down event loop"); - break - }, - event_loop_result = event_loop_future => { - event_loop_result? - } - }; - self.worker - .run_event_loop(self.maybe_coverage_collector.is_none()) - .await?; - - 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()) - //.map_err(|err| ferr!(Box::new(err))) - } - - 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, -} - -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 (tx, rx) = tokio::sync::oneshot::channel(); - self.sender - .send(ModuleWorkerReq::Run { - response_channel: tx, - }) - .await - .expect_or_log("channel error"); - Ok(( - 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<( - tokio::sync::oneshot::Receiver>, - tokio::sync::watch::Sender, - FinishedWorkerHandle, - )> { - let (term_signal_tx, term_signal_rx) = tokio::sync::watch::channel(false); - let (tx, rx) = tokio::sync::oneshot::channel(); - self.sender - .send(ModuleWorkerReq::DriveTillExit { - term_signal: term_signal_rx, - response_channel: tx, - }) - .await - .expect_or_log("channel error"); - Ok(( - rx, - term_signal_tx, - 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") - } -} - /// 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!). @@ -590,8 +59,8 @@ fn spawn_subcommand + 'static>(f: F) -> JoinHandle<()> { pub fn run_sync( main_mod: ModuleSpecifier, config_file: Option, - permissions: args::PermissionFlags, - custom_extensions: Arc, + permissions: deno::args::PermissionFlags, + custom_extensions: Arc, ) { new_thread_builder() .spawn(|| { @@ -613,14 +82,14 @@ pub fn run_sync( pub async fn run( main_module: ModuleSpecifier, config_file: Option, - permissions: args::PermissionFlags, - custom_extensions: Arc, + 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 = args::Flags { + let flags = deno::args::Flags { permissions, - unstable_config: args::UnstableConfig { + unstable_config: deno::args::UnstableConfig { features: DEFAULT_UNSTABLE_FLAGS .iter() .copied() @@ -629,7 +98,7 @@ pub async fn run( ..Default::default() }, config_flag: if let Some(config_file) = config_file { - args::ConfigFlag::Path(config_file) + deno::args::ConfigFlag::Path(config_file) } else { Default::default() }, @@ -638,7 +107,8 @@ pub async fn run( let flags = Arc::new(flags); - let cli_factory = factory::CliFactory::from_flags(flags).with_custom_ext_cb(custom_extensions); + 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?; @@ -653,12 +123,12 @@ pub async fn run( } pub fn test_sync( - files: deno_config::glob::FilePatterns, + files: deno::deno_config::glob::FilePatterns, config_file: PathBuf, - permissions: args::PermissionFlags, + permissions: deno::args::PermissionFlags, coverage_dir: Option, filter: Option, - custom_extensions: Arc, + custom_extensions: Arc, argv: Vec, ) { new_thread_builder() @@ -687,29 +157,31 @@ pub fn test_sync( } pub async fn test( - files: deno_config::glob::FilePatterns, + files: deno::deno_config::glob::FilePatterns, config_file: PathBuf, - permissions: args::PermissionFlags, + permissions: deno::args::PermissionFlags, coverage_dir: Option, filter: Option, - custom_extensions: Arc, + custom_extensions: Arc, argv: Vec, ) -> anyhow::Result<()> { use deno::tools::test::*; deno_permissions::set_prompt_callbacks( - Box::new(util::draw_thread::DrawThread::hide), - Box::new(util::draw_thread::DrawThread::show), + Box::new(deno::util::draw_thread::DrawThread::hide), + Box::new(deno::util::draw_thread::DrawThread::show), ); let pattern_to_str = |pattern| match pattern { - deno_config::glob::PathOrPattern::Path(path) => path.to_string_lossy().to_string(), - deno_config::glob::PathOrPattern::Pattern(pattern) => pattern.as_str().to_string(), - deno_config::glob::PathOrPattern::RemoteUrl(url) => url.as_str().to_owned(), - deno_config::glob::PathOrPattern::NegatedPath(path) => path.to_string_lossy().to_string(), + 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 = args::TestFlags { - files: args::FileFlags { + let test_flags = deno::args::TestFlags { + files: deno::args::FileFlags { include: files .include .clone() @@ -732,9 +204,9 @@ pub async fn test( concurrent_jobs: std::thread::available_parallelism().ok(), ..Default::default() }; - let flags = args::Flags { + let flags = deno::args::Flags { permissions, - unstable_config: args::UnstableConfig { + unstable_config: deno::args::UnstableConfig { features: DEFAULT_UNSTABLE_FLAGS .iter() .copied() @@ -742,20 +214,21 @@ pub async fn test( .collect(), ..Default::default() }, - type_check_mode: args::TypeCheckMode::Local, - config_flag: args::ConfigFlag::Path(config_file.to_string_lossy().into()), + type_check_mode: deno::args::TypeCheckMode::Local, + config_flag: deno::args::ConfigFlag::Path(config_file.to_string_lossy().into()), argv, - subcommand: args::DenoSubcommand::Test(test_flags.clone()), + subcommand: deno::args::DenoSubcommand::Test(test_flags.clone()), ..Default::default() }; let flags = Arc::new(flags); - let cli_factory = factory::CliFactory::from_flags(flags).with_custom_ext_cb(custom_extensions); + 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 = args::WorkspaceTestOptions { + let test_options = deno::args::WorkspaceTestOptions { // files, ..options.resolve_workspace_test_options(&test_flags) }; diff --git a/src/denort/promises.rs b/src/denort/promises.rs index 7692575..ade0ae4 100644 --- a/src/denort/promises.rs +++ b/src/denort/promises.rs @@ -36,24 +36,25 @@ where .take() .unwrap() } - let on_fulfilled = v8::Function::builder( + 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))); - }, - ) - .data(external.into()) - .build(scope); - let on_rejected = v8::Function::builder( + }; + 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))); - }, - ) - .data(external.into()) - .build(scope); + }; + 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); diff --git a/src/denort/unsync.rs b/src/denort/unsync.rs new file mode 100644 index 0000000..0a3acac --- /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 0000000..08c4b5b --- /dev/null +++ b/src/denort/worker.rs @@ -0,0 +1,562 @@ +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 thread and uses it to run all the tasks +/// that'll need to touch deno internals. Deno is single threaded. +/// +/// Returned handles 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 + .map_err(|err| ferr!(Box::new(err))), + ) + .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(|err| ferr!(Box::new(err))), + ) + .expect_or_log("channel error"), + ModuleWorkerReq::Execute { response_channel } => response_channel + .send( + module_cx + .execute_main_module() + .await + .map_err(|err| ferr!(Box::new(err))), + ) + .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(|err| ferr!(Box::new(err)))? + .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(|err| ferr!(Box::new(err)))? + .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(|err| ferr!(Box::new(err)))?; + let maybe_coverage_collector = worker + .maybe_setup_coverage_collector() + .await + .map_err(|err| ferr!(Box::new(err)))?; + + // 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() + .walk( + [&self.main_module].into_iter(), + deno::deno_graph::WalkOptions { + kind: deno::deno_graph::GraphKind::CodeOnly, + check_js: false, + follow_dynamic: true, + prefer_fast_check_graph: false, + }, + ) + .map(|(url, _)| url.clone()) + .collect() + } + + async fn run(&mut self, global_term_signal: TermSignal) -> anyhow::Result { + debug!("main_module {}", self.main_module); + self.execute_main_module().await?; + + let (_local_signal_tx, local_signal_rx) = tokio::sync::watch::channel(false); + self.drive_till_exit(global_term_signal, local_signal_rx) + .await + } + + 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(false).boxed_local(); + + 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 => { + event_loop_result? + } + }; + self.worker + .run_event_loop(self.maybe_coverage_collector.is_none()) + .await?; + + 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()) + //.map_err(|err| ferr!(Box::new(err))) + } + + 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, +} + +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 (tx, rx) = tokio::sync::oneshot::channel(); + self.sender + .send(ModuleWorkerReq::Run { + response_channel: tx, + }) + .await + .expect_or_log("channel error"); + Ok(( + 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<( + tokio::sync::oneshot::Receiver>, + tokio::sync::watch::Sender, + FinishedWorkerHandle, + )> { + let (term_signal_tx, term_signal_rx) = tokio::sync::watch::channel(false); + let (tx, rx) = tokio::sync::oneshot::channel(); + self.sender + .send(ModuleWorkerReq::DriveTillExit { + term_signal: term_signal_rx, + response_channel: tx, + }) + .await + .expect_or_log("channel error"); + Ok(( + rx, + term_signal_tx, + 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 index 834f567..c0964a1 100644 --- a/src/ghjk/Cargo.toml +++ b/src/ghjk/Cargo.toml @@ -55,7 +55,7 @@ tracing-futures = "0.2" async-trait = "0.1.83" futures-concurrency = "7.6.2" futures = { version = "=0.3.30", default-features = false, features = ["std", "async-await"] } -tokio = { workspace = true, features = ["full", "parking_lot"] } +tokio = { workspace = true, features = ["full", "parking_lot", "tracing"] } tokio-stream = "0.1" dashmap = { version = "5.5", features = ["serde"]} @@ -73,6 +73,9 @@ sha2 = "0.10.8" pathdiff = "0.2.2" directories = "5.0.1" +dialoguer = "0.11.0" +console = "0.15.8" +console-subscriber = "0.4.1" [build-dependencies] shadow-rs.workspace = true diff --git a/src/ghjk/cli.rs b/src/ghjk/cli.rs index 3be391f..437c7e9 100644 --- a/src/ghjk/cli.rs +++ b/src/ghjk/cli.rs @@ -15,6 +15,8 @@ pub async fn cli() -> Res { let config = Config::source().await?; + debug!("config sourced: {config:?}"); + let Some(quick_err) = try_quick_cli(&config).await? else { return Ok(ExitCode::SUCCESS); }; @@ -39,9 +41,13 @@ pub async fn cli() -> Res { .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(flags, Some(Arc::new(Vec::new))).await? + denort::worker::worker(flags, Some(Arc::new(Vec::new))).await? }; let gcx = GhjkCtx { diff --git a/src/ghjk/config.rs b/src/ghjk/config.rs index fbf0a10..767e456 100644 --- a/src/ghjk/config.rs +++ b/src/ghjk/config.rs @@ -64,7 +64,9 @@ impl Config { // 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?; + 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 { diff --git a/src/ghjk/ext.rs b/src/ghjk/ext.rs index da8a612..706f1dd 100644 --- a/src/ghjk/ext.rs +++ b/src/ghjk/ext.rs @@ -34,8 +34,11 @@ impl ExtConfig { Self::default() } - pub fn callbacks_handle(&mut self) -> callbacks::CallbacksHandle { - let (line, handle) = callbacks::CallbackLine::new(); + 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 diff --git a/src/ghjk/ext/callbacks.rs b/src/ghjk/ext/callbacks.rs index 6939b64..5a8def2 100644 --- a/src/ghjk/ext/callbacks.rs +++ b/src/ghjk/ext/callbacks.rs @@ -24,35 +24,43 @@ pub enum CallbackError { V8Error(eyre::Report), } +struct CallbackCtx { + rx: tokio::sync::mpsc::Receiver, + term_signal: tokio::sync::watch::Receiver, +} + /// Line used by the callback_worker to receive /// invocations. #[derive(Default)] pub struct CallbackLine { - line: Option>, + cx: Option, was_set: bool, } impl CallbackLine { - pub fn new() -> (Self, CallbacksHandle) { + pub fn new(dworker: &denort::worker::DenoWorkerHandle) -> (Self, CallbacksHandle) { let (tx, rx) = tokio::sync::mpsc::channel(1); ( Self { was_set: true, - line: Some(rx), + cx: Some(CallbackCtx { + rx, + term_signal: dworker.term_signal_watcher(), + }), }, CallbacksHandle { sender: tx }, ) } - fn take(&mut self) -> Option> { + fn take(&mut self) -> Option { if !self.was_set { - debug!("callback line was not set, worker callbacks will noop"); + // debug!("callback line was not set, worker callbacks will noop"); return None; } - match self.line.take() { + match self.cx.take() { Some(val) => Some(val), None => { - debug!("realm with callbacks just had a child, it won't inherit callback feature"); + // debug!("realm with callbacks just had a child, it won't inherit callback feature"); None } } @@ -107,23 +115,33 @@ pub struct Callbacks { /// Stored callbacks are not Sync so this expects to be started /// on the same thread as deno. pub fn worker(config: &ExtConfig) -> Option { - let mut line = config.callbacks_rx.lock().expect_or_log("mutex err"); - let mut line = line.take()?; + let CallbackCtx { + mut rx, + term_signal, + } = { + let mut mutex = config.callbacks_rx.lock().expect_or_log("mutex err"); + mutex.take()? + }; let callbacks = Callbacks::default(); let callbacks_2go = callbacks.clone(); - deno_core::unsync::spawn( + denort::unsync::spawn( + "callback-worker", async move { trace!("callback worker starting"); - while let Some(msg) = line.recv().await { - trace!(?msg, "callback worker msg"); + 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).await) + .send( + callbacks_2go + .exec_callback(name, args, term_signal.clone()) + .await, + ) .expect_or_log("channel error"), } } @@ -140,6 +158,7 @@ impl Callbacks { &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 { @@ -147,6 +166,11 @@ impl Callbacks { }); }; + 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 @@ -164,6 +188,7 @@ impl Callbacks { // 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, @@ -191,27 +216,31 @@ impl Callbacks { if res.is_promise() { let promise = v8::Local::::try_from(res).unwrap(); - 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"), - ) - }), - Err(err) => Err(CallbackError::JsError(ferr!( - "callback promise rejection: {}", - err.to_rust_string_lossy(scope) - ))), /* Err(err) => match serde_v8::from_v8(scope, err) { - Ok(json) => Err(CallbackError::JsError(json)), - Err(err) => Err(CallbackError::ProtocolError( - ferr!(err) - .wrap_err("error deserializaing promise rejection from v8"), - )), - }, */ - }; - tx.send(res).expect_or_log("channel error") - }); + if let None = + 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", + )) + }), + Err(err) => Err(CallbackError::JsError(ferr!( + "callback promise rejection: {}", + err.to_rust_string_lossy(scope) + ))), /* Err(err) => match serde_v8::from_v8(scope, err) { + Ok(json) => Err(CallbackError::JsError(json)), + Err(err) => Err(CallbackError::ProtocolError( + ferr!(err) + .wrap_err("error deserializaing promise rejection from v8"), + )), + }, */ + }; + tx.send(res).expect_or_log("channel error") + }) + { + return Err(CallbackError::V8Error(ferr!("js runtime is shutting down"))); + }; Ok(None) } else { let res = serde_v8::from_v8(scope, res).map_err(|err| { @@ -224,11 +253,18 @@ impl Callbacks { }) }); - let res = match join_handle.await.expect_or_log("tokio error")? { - Some(res) => res, - None => { - trace!("waiting for callback proimse"); - rx.await.expect_or_log("channel error")? + // 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")? } }; diff --git a/src/ghjk/host.rs b/src/ghjk/host.rs index 2f9e775..73ed645 100644 --- a/src/ghjk/host.rs +++ b/src/ghjk/host.rs @@ -1,3 +1,5 @@ +use std::io::IsTerminal; + use crate::interlude::*; use crate::systems::*; @@ -55,6 +57,7 @@ pub async fn systems_from_ghjkfile( ghjkdir_path.join("lock.json"), ); + // read both files concurrently let (hash_obj, lock_obj) = ( HashObj::from_file(&hashfile_path), LockObj::from_file(&lockfile_path), @@ -62,9 +65,38 @@ pub async fn systems_from_ghjkfile( .join() .await; + // discard corrupt files if needed let (mut hash_obj, mut lock_obj) = ( - hash_obj.inspect_err(|err| warn!("{err}")).ok(), - lock_obj.inspect_err(|err| warn!("{err}")).ok(), + 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 { @@ -80,10 +112,9 @@ pub async fn systems_from_ghjkfile( ( matches!(tokio::fs::try_exists(path).await, Ok(true)), Some( - hashfile::file_content_digest_hash(hcx.as_ref(), path) + hashfile::file_digest_hash(hcx.as_ref(), path) .await? - .await - .map_err(|err| ferr!(err))?, + .unwrap(), ), ) } else { @@ -98,10 +129,17 @@ pub async fn systems_from_ghjkfile( } 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(), ghjkfile_hash.as_ref().unwrap()) - .await?) + .await + .inspect(|is_stale| { + if *is_stale { + debug!("stale hashfile, discarding") + } + })?) { hash_obj = None; } @@ -253,12 +291,12 @@ impl GhjkfileSystems { warn!("locked flag set, changes to lockfile discarded"); } else { trace!(lockfile_path = ?self.lockfile_path, /* ?lock_obj, */ "writing lock.json"); - /* tokio::fs::write( + 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")?; */ + .wrap_err("error writing to lockfile")?; self.old_lock_obj.replace(lock_obj); } } @@ -270,13 +308,13 @@ impl GhjkfileSystems { unreachable!("code should have early exited"); } trace!(hashfile_path = ?self.hashfile_path, /* hash_obj= ?self.hash_obj, */ "writing hash.json"); - /* tokio::fs::write( + 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")?; */ + .wrap_err("error writing to lockfile")?; self.hashfile_written = true; } Ok(()) @@ -318,14 +356,24 @@ pub struct LockObj { pub config: Arc, } +#[derive(Debug, thiserror::Error)] +pub enum LockfileError { + #[error("error parsing lockfile:{0}")] + Serialization(serde_json::Error), + #[error("{0}")] + Other(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) -> Res { - let raw = tokio::fs::read(path) - .await - .wrap_err("error reading hash.json")?; - serde_json::from_slice(&raw).wrap_err("error parsing lock.json") + 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/hashfile.rs b/src/ghjk/host/hashfile.rs index 47423b8..038c9e8 100644 --- a/src/ghjk/host/hashfile.rs +++ b/src/ghjk/host/hashfile.rs @@ -16,6 +16,14 @@ pub struct HashObj { pub listed_files: Vec, } +#[derive(Debug, thiserror::Error)] +pub enum HashfileError { + #[error("error parsing hashfile: {0}")] + Serialization(serde_json::Error), + #[error("{0}")] + Other(eyre::Report), +} + impl HashObj { #[tracing::instrument(skip(hcx, res))] pub async fn from_result( @@ -52,15 +60,19 @@ impl HashObj { /// 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) -> Res { - let raw = tokio::fs::read(path) - .await - .wrap_err("error reading hash.json")?; - serde_json::from_slice(&raw).wrap_err("error parsing hash.json") + 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, ghjkfile_hash: &str) -> Res { if self.ghjkfile_hash != ghjkfile_hash { + trace!("stale ghjkfile hash"); return Ok(true); } { @@ -69,12 +81,14 @@ impl HashObj { 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); } } @@ -90,6 +104,7 @@ impl HashObj { ) .await? { + trace!("stale read files digest"); return Ok(true); } } @@ -128,7 +143,7 @@ async fn file_digests( Ok(out.into_iter().collect()) } -async fn file_digest_hash(hcx: &HostCtx, path: &Path) -> Res> { +pub async fn file_digest_hash(hcx: &HostCtx, path: &Path) -> Res> { let path = tokio::fs::canonicalize(path) .await .wrap_err("error resolving realpath")?; @@ -158,7 +173,7 @@ async fn file_digest_hash(hcx: &HostCtx, path: &Path) -> Res> { pub type SharedFileContentDigestFuture = futures::future::Shared>>; -pub async fn file_content_digest_hash( +async fn file_content_digest_hash( hcx: &HostCtx, path: &Path, ) -> Res { diff --git a/src/ghjk/log.rs b/src/ghjk/log.rs index 130b02f..bbb3b7c 100644 --- a/src/ghjk/log.rs +++ b/src/ghjk/log.rs @@ -84,12 +84,14 @@ Args: {args:?} let filter = tracing_subscriber::EnvFilter::from_default_env(); tracing_subscriber::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()) - .init(); + .with(console_subscriber::spawn()) + // 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()) + .init(); + // console_subscriber::init(); }); } diff --git a/src/ghjk/main.rs b/src/ghjk/main.rs index abbdb26..9c78c3e 100644 --- a/src/ghjk/main.rs +++ b/src/ghjk/main.rs @@ -69,6 +69,6 @@ shadow!(shadow); #[derive(Debug)] pub struct GhjkCtx { - deno: denort::DenoWorkerHandle, + deno: denort::worker::DenoWorkerHandle, config: config::Config, } diff --git a/src/ghjk/systems/deno.rs b/src/ghjk/systems/deno.rs index 738bfaa..a393c85 100644 --- a/src/ghjk/systems/deno.rs +++ b/src/ghjk/systems/deno.rs @@ -97,7 +97,7 @@ pub async fn systems_from_deno( .boxed() }), ); - let cb_line = ext_conf.callbacks_handle(); + let cb_line = ext_conf.callbacks_handle(&gcx.deno); let mut worker = gcx .deno @@ -144,16 +144,12 @@ pub async fn systems_from_deno( let err = match exit_code_channel.await.expect_or_log("channel error") { Ok(0) => return Ok(()), Ok(exit_code) => { - error!(%exit_code, "deno systems died with non-zero exit code"); - let err = ferr!("deno systems died with non-zero exit code: {exit_code}"); - error!("{err}"); - err + ferr!("deno systems died with non-zero exit code: {exit_code}") } Err(err) => err.wrap_err("error on event loop for deno systems"), }; - // TODO: better exit signals - debug!("killing whole deno context"); - dcx.terminate().await.unwrap(); + error!("deno systems error: {err:?}"); + dcx.terminate().await.expect_or_log("error terminating deno worker"); Err(err) }); diff --git a/src/ghjk/utils.rs b/src/ghjk/utils.rs index 3d7583c..937e0a3 100644 --- a/src/ghjk/utils.rs +++ b/src/ghjk/utils.rs @@ -19,7 +19,7 @@ mod cheapstr { }; // lifted from github.com/bevyengine/bevy 's bevy_core/Name struct // MIT/APACHE2 licence - #[derive(Debug, Clone, Serialize, Deserialize)] + #[derive(Clone, Serialize, Deserialize)] #[serde(crate = "serde", from = "String", into = "String")] pub struct CHeapStr { hash: u64, @@ -128,6 +128,12 @@ mod cheapstr { 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; @@ -238,18 +244,18 @@ pub async fn find_entry_recursive(from: &Path, name: &str) -> Res { + Ok(true) => { return Ok(Some(location)); } - Err(err) if err.kind() == std::io::ErrorKind::NotFound => { + 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; } - Err(err) => { - return Err(err).wrap_err("error on file stat"); - } } } } diff --git a/tests/envs.ts b/tests/envs.ts index 05106a7..c9c6b74 100644 --- a/tests/envs.ts +++ b/tests/envs.ts @@ -47,6 +47,7 @@ const envVarTestEnvs: EnvDefArgs[] = [ ]; const envVarTestsPosix = ` set -ex +env # by default, we should be in main [ "$SONG" = "ditto" ] || exit 1010 [ "$GHJK_ENV" = "main" ] || exit 1011 diff --git a/tests/utils.ts b/tests/utils.ts index b468677..87be25b 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -128,7 +128,7 @@ export async function localE2eTest(testCase: E2eTestCase) { const ghjkExePath = $.path(import.meta.resolve("../target/debug/ghjk")); - const env: Record = { + const env: Record = { GHJK_AUTO_HOOK: "true", BASH_ENV: `${ghjkDataDir.toString()}/env.bash`, ZDOTDIR: ghjkDataDir.toString(), @@ -139,6 +139,8 @@ export async function localE2eTest(testCase: E2eTestCase) { // share the system's deno cache GHJK_DENO_DIR: Deno.env.get("DENO_DIR") ?? $.path(Deno.env.get("HOME")!).join(".cache", "deno").toString(), + RUST_LOG: $.dbg(Deno.env.get("RUST_LOG"), "RUST_LOG"), + GHJK_LOG: Deno.env.get("GHJK_LOG"), ...testEnvs, }; // install ghjk From d484493ee0a6788d24ce9717a585fffc922e24a4 Mon Sep 17 00:00:00 2001 From: Yohe-Am <56622350+Yohe-Am@users.noreply.github.com> Date: Mon, 23 Dec 2024 17:36:09 +0100 Subject: [PATCH 07/13] wip: wip --- .ghjk/lock.json | 90 +++++++++++++++++++++++++++++++++++----- ghjk.ts | 2 +- src/ghjk/cli.rs | 2 +- src/ghjk/config.rs | 11 +++-- src/ghjk/log.rs | 16 +++---- src/ghjk/systems/deno.rs | 15 ++++--- tests/envs.ts | 1 + tests/utils.ts | 13 ++++-- 8 files changed, 118 insertions(+), 32 deletions(-) diff --git a/.ghjk/lock.json b/.ghjk/lock.json index ad0600a..aa6148d 100644 --- a/.ghjk/lock.json +++ b/.ghjk/lock.json @@ -14,7 +14,7 @@ "version": "4.0.1", "buildDepConfigs": { "cpy_bs_ghrel": { - "version": "3.12.7", + "version": "3.13.1", "buildDepConfigs": { "tar_aa": { "version": "1.35", @@ -38,7 +38,7 @@ "specifiedVersion": false }, "bciqh4dfyevkzzvmnhuz7lcfqttkg5neg4ewhoxzofyuicavgk6pb7ia": { - "version": "3.12.7", + "version": "3.13.1", "buildDepConfigs": { "tar_aa": { "version": "1.35", @@ -72,7 +72,7 @@ "version": "3.9.0.0", "buildDepConfigs": { "cpy_bs_ghrel": { - "version": "3.12.7", + "version": "3.13.1", "buildDepConfigs": { "tar_aa": { "version": "1.35", @@ -117,7 +117,7 @@ "version": "3.31.0.1", "buildDepConfigs": { "cpy_bs_ghrel": { - "version": "3.12.7", + "version": "3.13.1", "buildDepConfigs": { "tar_aa": { "version": "1.35", @@ -247,6 +247,74 @@ "rust-src" ], "specifiedVersion": true + }, + "bciqeosxosr6ur7pu7gny33gy7dqubmxbcs4775xazb4zvaxavkd5rha": { + "version": "0.1.13", + "buildDepConfigs": { + "cargo_binstall_ghrel": { + "version": "v1.10.17", + "buildDepConfigs": {}, + "portRef": "cargo_binstall_ghrel@0.1.0", + "specifiedVersion": false + }, + "rust_rustup": { + "version": "1.83.0", + "buildDepConfigs": { + "rustup_rustlang": { + "version": "1.27.1", + "buildDepConfigs": { + "git_aa": { + "version": "2.47.0", + "buildDepConfigs": {}, + "portRef": "git_aa@0.1.0", + "specifiedVersion": false + } + }, + "portRef": "rustup_rustlang@0.1.0", + "specifiedVersion": false + } + }, + "portRef": "rust_rustup@0.1.0", + "profile": "minimal", + "specifiedVersion": false + } + }, + "portRef": "cargobi_cratesio@0.1.0", + "crateName": "tokio-console", + "specifiedVersion": false + }, + "bciqeal5okt5zj763vhgsmf3afr5thrkqaitv6pb3wwegcwyb74gdyjq": { + "version": "v1.10.17", + "buildDepConfigs": {}, + "portRef": "cargo_binstall_ghrel@0.1.0", + "specifiedVersion": false + }, + "bciqeub366wrduva4y3rxegdjkhlebwsud56e5orgcpbkdrbhuxmvuxa": { + "version": "1.83.0", + "buildDepConfigs": { + "rustup_rustlang": { + "version": "1.27.1", + "buildDepConfigs": { + "git_aa": { + "version": "2.47.0", + "buildDepConfigs": {}, + "portRef": "git_aa@0.1.0", + "specifiedVersion": false + } + }, + "portRef": "rustup_rustlang@0.1.0", + "specifiedVersion": false + } + }, + "portRef": "rust_rustup@0.1.0", + "profile": "minimal", + "specifiedVersion": false + }, + "bciqe7g5m4v5jkg3ubqhogjjntsduyrwxcirqcp6tc3jmjr5af7ojq6a": { + "version": "v2.1.2", + "buildDepConfigs": {}, + "portRef": "deno_ghrel@0.1.0", + "specifiedVersion": true } } }, @@ -270,7 +338,7 @@ "bciqpu4klxr3hl6ujhmflrlfd3dxp47ijq26mnathb26ojzwkeggy5ii", "bciqelae2kzmf7umbo62flzq2mnlhnc4ilbfmn4va2fzrqwx7w7zusji" ], - "allowedBuildDeps": "bciqoo3t36t4pphdox5wa5ugn34wkar7rwkqgb5l55lwnxbuabcc3nyq" + "allowedBuildDeps": "bciqe3wvwtylh2xeobipylsfxihnx5fhjixmozyxjsn6gnwk5vikvxxi" }, "ghjkEnvProvInstSet____rust": { "installs": [ @@ -282,7 +350,7 @@ "bciqpu4klxr3hl6ujhmflrlfd3dxp47ijq26mnathb26ojzwkeggy5ii", "bciqelae2kzmf7umbo62flzq2mnlhnc4ilbfmn4va2fzrqwx7w7zusji" ], - "allowedBuildDeps": "bciqoo3t36t4pphdox5wa5ugn34wkar7rwkqgb5l55lwnxbuabcc3nyq" + "allowedBuildDeps": "bciqe3wvwtylh2xeobipylsfxihnx5fhjixmozyxjsn6gnwk5vikvxxi" }, "ghjkEnvProvInstSet___dev": { "installs": [ @@ -296,7 +364,7 @@ "bciqpu4klxr3hl6ujhmflrlfd3dxp47ijq26mnathb26ojzwkeggy5ii", "bciqelae2kzmf7umbo62flzq2mnlhnc4ilbfmn4va2fzrqwx7w7zusji" ], - "allowedBuildDeps": "bciqoo3t36t4pphdox5wa5ugn34wkar7rwkqgb5l55lwnxbuabcc3nyq" + "allowedBuildDeps": "bciqe3wvwtylh2xeobipylsfxihnx5fhjixmozyxjsn6gnwk5vikvxxi" }, "ghjkEnvProvInstSet_______task_env_cache-v8": { "installs": [], @@ -509,7 +577,7 @@ "moduleSpecifier": "file:///ports/deno_ghrel.ts" } }, - "bciqakxf4wsx3mtku4x5exrl44k4r4kyq6gaw4va5hsb3v26cipmmekq": { + "bciqdfarczmlu3r5dkvcdoultfbnuvn6saao55h4fbb3jg72kv6mkr3y": { "manifest": { "ty": "denoWorker@v1", "name": "cpy_bs_ghrel", @@ -533,7 +601,7 @@ "moduleSpecifier": "file:///ports/cpy_bs.ts" }, "defaultInst": { - "version": "3.12.7", + "version": "3.13.1", "portRef": "cpy_bs_ghrel@0.1.0" } }, @@ -805,8 +873,8 @@ "portRef": "asdf_plugin_git@0.1.0" } }, - "bciqoo3t36t4pphdox5wa5ugn34wkar7rwkqgb5l55lwnxbuabcc3nyq": { - "cpy_bs_ghrel": "bciqakxf4wsx3mtku4x5exrl44k4r4kyq6gaw4va5hsb3v26cipmmekq", + "bciqe3wvwtylh2xeobipylsfxihnx5fhjixmozyxjsn6gnwk5vikvxxi": { + "cpy_bs_ghrel": "bciqdfarczmlu3r5dkvcdoultfbnuvn6saao55h4fbb3jg72kv6mkr3y", "tar_aa": "bciqb6ua63xodzwxngnbjq35hfikiwzb3dclbqkc7e6xgjdt5jin4pia", "git_aa": "bciqfl5s36w335ducrb6f6gwb3vuwup7vzqwwg67pq42xtkngsnxqobi", "curl_aa": "bciqcfe7qyxmokpn6pgtaj35r5qg74jkehuu6cvyrtcsnegvwlm64oqy", diff --git a/ghjk.ts b/ghjk.ts index 6c209e7..1f0124b 100644 --- a/ghjk.ts +++ b/ghjk.ts @@ -11,7 +11,7 @@ import { unarchive } from "./utils/unarchive.ts"; config({ defaultEnv: "dev", enableRuntimes: true, - allowedBuildDeps: [ports.cpy_bs({ version: "3.12.7" })], + allowedBuildDeps: [ports.cpy_bs({ version: "3.13.1" })], }); env("main").vars({ diff --git a/src/ghjk/cli.rs b/src/ghjk/cli.rs index 437c7e9..40aada0 100644 --- a/src/ghjk/cli.rs +++ b/src/ghjk/cli.rs @@ -92,7 +92,7 @@ pub async fn cli() -> Res { let mut root_cmd = Cli::command(); - debug!("colleting system commands"); + debug!("collecting system commands"); let (sys_cmds, sys_actions) = match commands_from_systems(&systems).await { Ok(val) => val, diff --git a/src/ghjk/config.rs b/src/ghjk/config.rs index 767e456..619a231 100644 --- a/src/ghjk/config.rs +++ b/src/ghjk/config.rs @@ -248,9 +248,14 @@ hash.json", }; } 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")?; + self.repo_root = dbg!( + deno_core::resolve_url_or_path(&path, cwd) + .map_err(|err| ferr!(Box::new(err))) + .wrap_err("error resolving repo_root")?, + &path, + cwd + ) + .0; } Ok(()) } diff --git a/src/ghjk/log.rs b/src/ghjk/log.rs index bbb3b7c..3f4a8c5 100644 --- a/src/ghjk/log.rs +++ b/src/ghjk/log.rs @@ -84,14 +84,14 @@ Args: {args:?} let filter = tracing_subscriber::EnvFilter::from_default_env(); tracing_subscriber::registry() - .with(console_subscriber::spawn()) - // 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()) - .init(); + .with(console_subscriber::spawn()) + // 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()) + .init(); // console_subscriber::init(); }); } diff --git a/src/ghjk/systems/deno.rs b/src/ghjk/systems/deno.rs index a393c85..5c38424 100644 --- a/src/ghjk/systems/deno.rs +++ b/src/ghjk/systems/deno.rs @@ -141,15 +141,20 @@ pub async fn systems_from_deno( let dcx = gcx.deno.clone(); let join_exit_code_watcher = tokio::spawn(async { - let err = match exit_code_channel.await.expect_or_log("channel error") { - Ok(0) => return Ok(()), - Ok(exit_code) => { + let err = match exit_code_channel.await { + Ok(Ok(0)) => return Ok(()), + Ok(Ok(exit_code)) => { ferr!("deno systems died with non-zero exit code: {exit_code}") } - Err(err) => err.wrap_err("error on event loop for deno systems"), + Ok(Err(err)) => err.wrap_err("error on event loop for deno systems"), + Err(_) => { + ferr!("deno systems unexpected shutdown") + } }; error!("deno systems error: {err:?}"); - dcx.terminate().await.expect_or_log("error terminating deno worker"); + dcx.terminate() + .await + .expect_or_log("error terminating deno worker"); Err(err) }); diff --git a/tests/envs.ts b/tests/envs.ts index c9c6b74..d684a40 100644 --- a/tests/envs.ts +++ b/tests/envs.ts @@ -58,6 +58,7 @@ ghjk_deactivate [ "$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 diff --git a/tests/utils.ts b/tests/utils.ts index 87be25b..a407573 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -127,13 +127,20 @@ export async function localE2eTest(testCase: E2eTestCase) { ); 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: `${ghjkExePath.parentOrThrow().toString()}:${Deno.env.get("PATH")}`, + PATH: `${ghjkShimPath.parentOrThrow().toString()}:${Deno.env.get("PATH")}`, HOME: tmpDir.toString(), GHJK_REPO_ROOT: import.meta.resolve("../"), // share the system's deno cache @@ -151,11 +158,11 @@ export async function localE2eTest(testCase: E2eTestCase) { shellsToHook: [], }); - await $`${ghjkExePath} print config` + await $`ghjk print config` .cwd(tmpDir.toString()) .clearEnv() .env(env); - await $`${ghjkExePath} envs cook` + await $`ghjk envs cook` .cwd(tmpDir.toString()) .clearEnv() .env(env); From dbcd420b89a7a2e3ff227d0536243a9711d7c7fa Mon Sep 17 00:00:00 2001 From: Yohe-Am <56622350+Yohe-Am@users.noreply.github.com> Date: Wed, 25 Dec 2024 17:01:23 +0300 Subject: [PATCH 08/13] fix: broken tests --- .ghjk/lock.json | 94 +++++++++++----------- .github/workflows/tests.yml | 22 +----- deno.jsonc | 2 +- ghjk.ts | 32 ++++---- modules/envs/mod.ts | 43 ++++++---- modules/envs/posix.ts | 1 + rust-toolchain.toml | 6 ++ scripts/dev.ts | 9 +++ src/deno_systems/bindings.ts | 1 + src/ghjk/Cargo.toml | 2 +- src/ghjk/cli.rs | 8 +- src/ghjk/config.rs | 19 +++-- src/ghjk/log.rs | 8 +- src/ghjk/systems/deno.rs | 6 +- src/ghjk/systems/deno/cli.rs | 4 +- tests/test-alpine.Dockerfile | 80 ------------------- tests/test.Dockerfile | 71 ----------------- tests/test.Dockerfile.dockerignore | 4 - tests/utils.ts | 122 ++++------------------------- 19 files changed, 159 insertions(+), 375 deletions(-) create mode 100644 rust-toolchain.toml delete mode 100644 tests/test-alpine.Dockerfile delete mode 100644 tests/test.Dockerfile delete mode 100644 tests/test.Dockerfile.dockerignore diff --git a/.ghjk/lock.json b/.ghjk/lock.json index aa6148d..1628909 100644 --- a/.ghjk/lock.json +++ b/.ghjk/lock.json @@ -338,7 +338,7 @@ "bciqpu4klxr3hl6ujhmflrlfd3dxp47ijq26mnathb26ojzwkeggy5ii", "bciqelae2kzmf7umbo62flzq2mnlhnc4ilbfmn4va2fzrqwx7w7zusji" ], - "allowedBuildDeps": "bciqe3wvwtylh2xeobipylsfxihnx5fhjixmozyxjsn6gnwk5vikvxxi" + "allowedBuildDeps": "bciqdg64uhkvlkqyc7nli33cja3aolbcdr75qepnrhj5ojlifsvxqzgq" }, "ghjkEnvProvInstSet____rust": { "installs": [ @@ -350,7 +350,7 @@ "bciqpu4klxr3hl6ujhmflrlfd3dxp47ijq26mnathb26ojzwkeggy5ii", "bciqelae2kzmf7umbo62flzq2mnlhnc4ilbfmn4va2fzrqwx7w7zusji" ], - "allowedBuildDeps": "bciqe3wvwtylh2xeobipylsfxihnx5fhjixmozyxjsn6gnwk5vikvxxi" + "allowedBuildDeps": "bciqdg64uhkvlkqyc7nli33cja3aolbcdr75qepnrhj5ojlifsvxqzgq" }, "ghjkEnvProvInstSet___dev": { "installs": [ @@ -364,7 +364,7 @@ "bciqpu4klxr3hl6ujhmflrlfd3dxp47ijq26mnathb26ojzwkeggy5ii", "bciqelae2kzmf7umbo62flzq2mnlhnc4ilbfmn4va2fzrqwx7w7zusji" ], - "allowedBuildDeps": "bciqe3wvwtylh2xeobipylsfxihnx5fhjixmozyxjsn6gnwk5vikvxxi" + "allowedBuildDeps": "bciqdg64uhkvlkqyc7nli33cja3aolbcdr75qepnrhj5ojlifsvxqzgq" }, "ghjkEnvProvInstSet_______task_env_cache-v8": { "installs": [], @@ -447,7 +447,7 @@ } ] }, - "bciqdngvsrwedhravpw6h4lzku6f52ljmexs6sqrtowntcqpguibfgti": { + "bciqkyp5qbfd3frv2e5hou4mgrlcodb5eaidc43el63bonty4i3thlya": { "provides": [ { "ty": "posix.envVar", @@ -457,7 +457,7 @@ { "ty": "posix.envVar", "key": "RUSTY_V8_MIRROR", - "val": "/home/yohe/ghjk/.dev/rusty_v8" + "val": "/var/home/asdf/repos/ecma/ghjk/.dev/rusty_v8" }, { "ty": "ghjk.ports.InstallSetRef", @@ -470,7 +470,7 @@ "envsNamed": { "main": "bciqonpyvifzte5gf6tl7gtk3ep5q3vst2gqncuznf3kav4mzbuvnpai", "_rust": "bciqm4lt7lvjdt3qzudw24qe4brezcej3ilxxhbmgfo2gdbfmh4j3a7i", - "dev": "bciqdngvsrwedhravpw6h4lzku6f52ljmexs6sqrtowntcqpguibfgti" + "dev": "bciqkyp5qbfd3frv2e5hou4mgrlcodb5eaidc43el63bonty4i3thlya" } } } @@ -605,6 +605,47 @@ "portRef": "cpy_bs_ghrel@0.1.0" } }, + "bciqgze4knhjfbiypt5axkjslfsduq6tbwszbiuy5zsgpacrm5h6cg4a": { + "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": { + "version": "1.82.0", + "portRef": "rust_rustup@0.1.0", + "profile": "default", + "components": [ + "rust-src" + ] + } + }, "bciqb6ua63xodzwxngnbjq35hfikiwzb3dclbqkc7e6xgjdt5jin4pia": { "manifest": { "ty": "ambientAccess@v1", @@ -807,43 +848,6 @@ "portRef": "node_org@0.1.0" } }, - "bciqhjmjvlo4aqvwxjkrmoiledobmhkfe7iovqe3wndxiw2aootwn4lq": { - "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", - "profile": "minimal" - } - }, "bciqoxx4uhfhw77sux6kzqhy6bvxhxkk4cqigrxdrmggillzkfjgjnli": { "manifest": { "ty": "denoWorker@v1", @@ -873,8 +877,9 @@ "portRef": "asdf_plugin_git@0.1.0" } }, - "bciqe3wvwtylh2xeobipylsfxihnx5fhjixmozyxjsn6gnwk5vikvxxi": { + "bciqdg64uhkvlkqyc7nli33cja3aolbcdr75qepnrhj5ojlifsvxqzgq": { "cpy_bs_ghrel": "bciqdfarczmlu3r5dkvcdoultfbnuvn6saao55h4fbb3jg72kv6mkr3y", + "rust_rustup": "bciqgze4knhjfbiypt5axkjslfsduq6tbwszbiuy5zsgpacrm5h6cg4a", "tar_aa": "bciqb6ua63xodzwxngnbjq35hfikiwzb3dclbqkc7e6xgjdt5jin4pia", "git_aa": "bciqfl5s36w335ducrb6f6gwb3vuwup7vzqwwg67pq42xtkngsnxqobi", "curl_aa": "bciqcfe7qyxmokpn6pgtaj35r5qg74jkehuu6cvyrtcsnegvwlm64oqy", @@ -883,7 +888,6 @@ "rustup_rustlang": "bciqk4ivbyqvpxwcaj5reufmveqldiizo6xmqiqq7njtaczgappydoka", "cargo_binstall_ghrel": "bciqpgt5wsiw4y7qzovqbt2yrdgq5mvhhjpcg6cxzt4w4taudyen44ca", "node_org": "bciqboouqnp54fnumgxvl7uay2k6ho4vhlbibvgoyyt5yt3rkwqaohzi", - "rust_rustup": "bciqhjmjvlo4aqvwxjkrmoiledobmhkfe7iovqe3wndxiw2aootwn4lq", "asdf_plugin_git": "bciqoxx4uhfhw77sux6kzqhy6bvxhxkk4cqigrxdrmggillzkfjgjnli" }, "bciqikjfnbntvagpghawbzlfp2es6lnqzhba3qx5de7tdrmvhuzhsjqa": { diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 19763f7..5cdbccd 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -9,13 +9,10 @@ on: - ready_for_review env: - 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: @@ -29,9 +26,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: denoland/setup-deno@v1 - with: - deno-version: ${{ env.DENO_VERSION }} # run ghjk once to avoid trigger file changes when # pre commit runs ghjk. We'll always see changes # to lock.json since GITHUB_TOKEN is different @@ -49,32 +43,20 @@ 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: denoland/setup-deno@v1 - with: - deno-version: ${{ env.DENO_VERSION }} - name: Cache deno dir uses: actions/cache@v4 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' }}" run: | # we need coreutils on max for the `timeout` command @@ -83,9 +65,7 @@ jobs: - 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 + - run: deno task test test-action: runs-on: ubuntu-latest diff --git a/deno.jsonc b/deno.jsonc index 6ae9b9b..ce5a3f9 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -1,7 +1,7 @@ { "tasks": { "test": "cargo build -p ghjk && deno test --unstable-worker-options --unstable-kv -A tests/*", - "self": "deno run -A --unstable-kv --unstable-worker-options main.ts ", + "self": "cargo run -p ghjk", "cache": "deno cache deps/*", "check": "deno run -A ./scripts/check.ts", "dev": "deno run -A ./scripts/dev.ts" diff --git a/ghjk.ts b/ghjk.ts index 1f0124b..30aa000 100644 --- a/ghjk.ts +++ b/ghjk.ts @@ -8,10 +8,21 @@ import { sedLock } from "./std.ts"; import { downloadFile, DownloadFileArgs } from "./utils/mod.ts"; import { unarchive } from "./utils/unarchive.ts"; +// keep in sync with deno's reqs +const RUST_VERSION = "1.82.0"; + +const installs = { + rust: ports.rust({ + version: RUST_VERSION, + profile: "default", + components: ["rust-src"], + }), +}; + config({ defaultEnv: "dev", enableRuntimes: true, - allowedBuildDeps: [ports.cpy_bs({ version: "3.13.1" })], + allowedBuildDeps: [ports.cpy_bs({ version: "3.13.1" }), installs.rust], }); env("main").vars({ @@ -21,14 +32,10 @@ env("main").vars({ env("_rust") .install( + // TODO: cmake ports.protoc(), ports.pipi({ packageName: "cmake" })[0], - // keep in sync with deno's reqs - ports.rust({ - version: "1.82.0", - profile: "default", - components: ["rust-src"], - }), + installs.rust, ); const RUSTY_V8_MIRROR = `${import.meta.dirname}/.dev/rusty_v8`; @@ -115,6 +122,9 @@ task( $.path(import.meta.dirname!), { lines: { + "./rust-toolchain.toml": [ + [/^(channel = ").*(")/, RUST_VERSION], + ], "./Cargo.toml": [ [/^(version = ").*(")/, GHJK_VERSION], ], @@ -124,15 +134,9 @@ task( "./host/mod.ts": [ [/(GHJK_VERSION = ").*(")/, GHJK_VERSION], ], - "./install.sh": [ - [/(GHJK_VERSION="\$\{GHJK_VERSION:-v).*(\}")/, GHJK_VERSION], - [/(DENO_VERSION="\$\{DENO_VERSION:-v).*(\}")/, DENO_VERSION], - ], "./tests/test.Dockerfile": [ [/(ARG DENO_VERSION=).*()/, DENO_VERSION], - ], - "./tests/test-alpine.Dockerfile": [ - [/(ARG DENO_VERSION=).*()/, DENO_VERSION], + [/(ARG RUST_VERSION=).*()/, RUST_VERSION], ], "./docs/*.md": [ [ diff --git a/modules/envs/mod.ts b/modules/envs/mod.ts index 1568484..d068c17 100644 --- a/modules/envs/mod.ts +++ b/modules/envs/mod.ts @@ -100,7 +100,7 @@ export class EnvsModule extends ModuleBase { }, }; - const commonArgs = { + const commonArgs: CliCommand["args"] = { envKey: { value_name: "ENV KEY", }, @@ -134,7 +134,7 @@ export class EnvsModule extends ModuleBase { name: "activate", about: `Activate an environment.`, before_long_help: - `- If no [envName] is specified and no env is currently active, this activates the configured default env [${ecx.config.defaultEnv}].`, + `- If no ENV KEY is specified and no env is currently active, this activates the configured default env [${ecx.config.defaultEnv}].`, flags: { ...commonFlags, }, @@ -144,12 +144,14 @@ export class EnvsModule extends ModuleBase { action: async function ( { flags: { taskEnv: taskKeyMaybe }, - args: { envName: envKeyMaybe }, + args: { envKey: envKeyMaybe }, }, ) { const { envKey } = envKeyArgs({ taskKeyMaybe: taskKeyMaybe as string, - envKeyMaybe: envKeyMaybe as string, + envKeyMaybe: (Array.isArray(envKeyMaybe) + ? envKeyMaybe[0] + : envKeyMaybe) as string, }); await activateEnv(envKey); }, @@ -158,7 +160,7 @@ export class EnvsModule extends ModuleBase { name: "cook", about: `Cooks the environment to a posix shell.`, before_long_help: - `- If no [envName] is specified, this will cook the active env [${ecx.activeEnv}]`, + `- If no ENV KEY is specified, this will cook the active env [${ecx.activeEnv}]`, flags: { ...commonFlags, }, @@ -168,12 +170,20 @@ export class EnvsModule extends ModuleBase { action: async function ( { flags: { taskEnv: taskKeyMaybe }, - args: { envName: envKeyMaybe }, + args: { envKey: envKeyMaybe }, }, ) { const { envKey, envName } = envKeyArgs({ taskKeyMaybe: taskKeyMaybe as string, - envKeyMaybe: envKeyMaybe as string, + envKeyMaybe: (Array.isArray(envKeyMaybe) + ? envKeyMaybe[0] + : envKeyMaybe) as string, + }); + $.dbg("activating env", { + envKey, + envKeyMaybe, + taskKeyMaybe, + envName, }); await reduceAndCookEnv(gcx, ecx, envKey, envName ?? envKey); }, @@ -183,8 +193,8 @@ export class EnvsModule extends ModuleBase { 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}].`, +- 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, }, @@ -194,12 +204,14 @@ export class EnvsModule extends ModuleBase { action: async function ( { flags: { taskEnv: taskKeyMaybe }, - args: { envName: envKeyMaybe }, + args: { envKey: envKeyMaybe }, }, ) { const { envKey } = envKeyArgs({ taskKeyMaybe: taskKeyMaybe as string, - envKeyMaybe: envKeyMaybe as string, + envKeyMaybe: (Array.isArray(envKeyMaybe) + ? envKeyMaybe[0] + : envKeyMaybe) as string, }); const env = ecx.config.envs[envKey]; if (!env) { @@ -215,7 +227,7 @@ export class EnvsModule extends ModuleBase { name: "sync", about: "Synchronize your shell to what's in your config.", before_long_help: `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 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, @@ -224,11 +236,13 @@ export class EnvsModule extends ModuleBase { ...commonArgs, }, action: async function ( - { flags: { taskEnv: taskKeyMaybe }, args: { envName: envKeyMaybe } }, + { flags: { taskEnv: taskKeyMaybe }, args: { envKey: envKeyMaybe } }, ) { const { envKey, envName } = envKeyArgs({ taskKeyMaybe: taskKeyMaybe as string, - envKeyMaybe: envKeyMaybe as string, + envKeyMaybe: (Array.isArray(envKeyMaybe) + ? envKeyMaybe[0] + : envKeyMaybe) as string, }); await reduceAndCookEnv( gcx, @@ -322,6 +336,7 @@ async function reduceAndCookEnv( const namedDir = $.path(gcx.ghjkDir).join("envs", name); await $.removeIfExists(namedDir); await namedDir.symlinkTo(envDir, { kind: "relative" }); + $.dbg(`linking ${name} to ${envKey}`); } if (name == ecx.config.defaultEnv || key == ecx.config.defaultEnv) { const defaultEnvDir = $.path(gcx.ghjkDir).join("envs", "default"); diff --git a/modules/envs/posix.ts b/modules/envs/posix.ts index e9d0f21..e729b0c 100644 --- a/modules/envs/posix.ts +++ b/modules/envs/posix.ts @@ -201,6 +201,7 @@ async function writeActivators( onEnterHooks: [string, string[]][], onExitHooks: [string, string[]][], ) { + $.dbg("writing activators", { envVars, pathVars, onEnterHooks, onExitHooks }); const ghjkDirVar = "_ghjk_dir"; const shareDirVar = "_ghjk_share_dir"; pathVars = { diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..762d4cf --- /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/dev.ts b/scripts/dev.ts index 2fdad21..65b2577 100755 --- a/scripts/dev.ts +++ b/scripts/dev.ts @@ -19,6 +19,15 @@ 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(), diff --git a/src/deno_systems/bindings.ts b/src/deno_systems/bindings.ts index 84e3021..8f2e4ed 100644 --- a/src/deno_systems/bindings.ts +++ b/src/deno_systems/bindings.ts @@ -151,6 +151,7 @@ function commandBinding(commandRaw: CliCommand): CliCommandBindedX { `sys_cli_command_action_${command.name}_${actionId}`, async (args) => { const actionArgs = bindingTypes.cliActionArgs.parse(args); + $.dbg("actionArgs", {actionArgs, command}); await action(actionArgs); return {}; }, diff --git a/src/ghjk/Cargo.toml b/src/ghjk/Cargo.toml index c0964a1..1546cbc 100644 --- a/src/ghjk/Cargo.toml +++ b/src/ghjk/Cargo.toml @@ -75,7 +75,7 @@ pathdiff = "0.2.2" directories = "5.0.1" dialoguer = "0.11.0" console = "0.15.8" -console-subscriber = "0.4.1" +console-subscriber = { version = "0.4.1", optional = true } [build-dependencies] shadow-rs.workspace = true diff --git a/src/ghjk/cli.rs b/src/ghjk/cli.rs index 40aada0..f4c08ca 100644 --- a/src/ghjk/cli.rs +++ b/src/ghjk/cli.rs @@ -56,7 +56,7 @@ pub async fn cli() -> Res { }; let gcx = Arc::new(gcx); - let systems_deno = systems::deno::systems_from_deno( + let (systems_deno, deno_sys_cx) = systems::deno::systems_from_deno( &gcx, &gcx.config .repo_root @@ -108,6 +108,8 @@ pub async fn cli() -> Res { root_cmd = root_cmd.subcommand(cmd.styles(CLAP_STYLE)); } + debug!("checking argv matches"); + let matches = match root_cmd.try_get_matches() { Ok(val) => val, Err(err) => { @@ -147,6 +149,7 @@ pub async fn cli() -> Res { } }; + debug!(?cmd_path, "system command found"); let Some(action) = action.action else { systems.write_lockfile_or_log().await; action.clap.print_long_help()?; @@ -155,10 +158,11 @@ pub async fn cli() -> Res { let res = action(action_matches.clone()) .await - .wrap_err_with(|| format!("errror on system command at path {cmd_path:?}")); + .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) diff --git a/src/ghjk/config.rs b/src/ghjk/config.rs index 619a231..d5f937f 100644 --- a/src/ghjk/config.rs +++ b/src/ghjk/config.rs @@ -89,8 +89,6 @@ impl Config { if cfg!(debug_assertions) { url::Url::from_file_path(&cwd) .expect_or_log("cwd error") - // repo root url must end in slash due to - // how Url::join works .join(&format!("{}/", cwd.file_name().unwrap().to_string_lossy())) .wrap_err("repo url error")? } else { @@ -131,6 +129,12 @@ impl 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 @@ -248,14 +252,9 @@ hash.json", }; } if let Some(path) = repo_root { - self.repo_root = dbg!( - deno_core::resolve_url_or_path(&path, cwd) - .map_err(|err| ferr!(Box::new(err))) - .wrap_err("error resolving repo_root")?, - &path, - cwd - ) - .0; + 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(()) } diff --git a/src/ghjk/log.rs b/src/ghjk/log.rs index 3f4a8c5..cc0505f 100644 --- a/src/ghjk/log.rs +++ b/src/ghjk/log.rs @@ -83,8 +83,12 @@ Args: {args:?} let filter = tracing_subscriber::EnvFilter::from_default_env(); - tracing_subscriber::registry() - .with(console_subscriber::spawn()) + let registry = tracing_subscriber::registry(); + + #[cfg(feature = "console-subscriber")] + let registry = registry.with(console_subscriber::spawn()); + + registry // filter on values from RUST_LOG .with(filter) // subscriber that emits to stderr diff --git a/src/ghjk/systems/deno.rs b/src/ghjk/systems/deno.rs index 5c38424..c692ce0 100644 --- a/src/ghjk/systems/deno.rs +++ b/src/ghjk/systems/deno.rs @@ -18,7 +18,7 @@ pub struct DenoSystemsContext { impl DenoSystemsContext { #[allow(unused)] - pub async fn terminate(&mut self) -> Res<()> { + pub async fn terminate(mut self) -> Res<()> { let channel = { let mut opt = self.exit_code_channel.lock().expect_or_log("mutex error"); opt.take() @@ -36,7 +36,7 @@ pub async fn systems_from_deno( gcx: &GhjkCtx, source_uri: &url::Url, ghjkdir_path: &Path, -) -> Res> { +) -> Res<(HashMap, DenoSystemsContext)> { let main_module = gcx .config .repo_root @@ -180,7 +180,7 @@ pub async fn systems_from_deno( }) .collect(); - Ok(manifests) + Ok((manifests, scx)) } #[derive(Debug, Deserialize)] diff --git a/src/ghjk/systems/deno/cli.rs b/src/ghjk/systems/deno/cli.rs index 221b4b9..9692d5b 100644 --- a/src/ghjk/systems/deno/cli.rs +++ b/src/ghjk/systems/deno/cli.rs @@ -138,7 +138,8 @@ async fn deno_cb_action( bucket.insert(id.as_str().to_owned(), value); } - scx.callbacks + let response = scx + .callbacks .exec( cb_key.clone(), serde_json::json!({ @@ -148,6 +149,7 @@ async fn deno_cb_action( ) .await .wrap_err("callback error")?; + debug!(?response, "system command action response"); Ok(()) } diff --git a/tests/test-alpine.Dockerfile b/tests/test-alpine.Dockerfile deleted file mode 100644 index c081d7a..0000000 --- a/tests/test-alpine.Dockerfile +++ /dev/null @@ -1,80 +0,0 @@ -ARG DENO_VERSION=2.1.2 - -FROM docker.io/denoland/deno:alpine-${DENO_VERSION} - -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,87 +16,15 @@ 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; + tsGhjkfileStr: string; + 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("$", "$$$$"), - )); - - if (dockerCmd[0] == "podman") { - await $ - .raw`${dockerCmd} buildah build ${dockerPlatform} ${ - Object.entries(env).map(([key, val]) => ["--build-arg", `${key}=${val}`]) - } --tag '${tag}' --network=host -- -f- .` - .env(env) - .stdinText(dFile); - } else { - 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; @@ -130,7 +46,7 @@ export async function localE2eTest(testCase: E2eTestCase) { const ghjkShimPath = await ghjkDataDir .join("ghjk") .writeText( - `!#/bin/sh + `#!/bin/sh exec ${ghjkExePath.resolve().toString()} "$@"`, { mode: 0o700 }, ); @@ -253,17 +169,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) { From d595decac61a3bba704dd92cf0dd6622f84f8805 Mon Sep 17 00:00:00 2001 From: Yohe-Am <56622350+Yohe-Am@users.noreply.github.com> Date: Wed, 25 Dec 2024 17:18:08 +0300 Subject: [PATCH 09/13] fix: pre-commit job --- .github/workflows/tests.yml | 5 +- ghjk.ts | 7 - host/mod.ts | 627 ----------------------------------- main.ts | 43 --- modules/envs/mod.ts | 7 - modules/envs/posix.ts | 1 - src/deno_systems/bindings.ts | 1 - src/ghjk/ext/callbacks.rs | 18 +- tests/todo.ts | 2 + tests/utils.ts | 2 +- 10 files changed, 16 insertions(+), 697 deletions(-) delete mode 100644 host/mod.ts delete mode 100755 main.ts create mode 100644 tests/todo.ts diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5cdbccd..84f6f13 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -26,11 +26,12 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - uses: dsherret/rust-toolchain-file@v1 # run ghjk once to avoid trigger file changes when # 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 print config - uses: pre-commit/action@v3.0.1 env: SKIP: ghjk-resolve @@ -52,6 +53,7 @@ jobs: # - os: windows-latest steps: - uses: actions/checkout@v4 + - uses: dsherret/rust-toolchain-file@v1 - name: Cache deno dir uses: actions/cache@v4 with: @@ -71,6 +73,7 @@ jobs: 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 diff --git a/ghjk.ts b/ghjk.ts index 30aa000..79f2e7a 100644 --- a/ghjk.ts +++ b/ghjk.ts @@ -131,13 +131,6 @@ task( "./.github/workflows/*.yml": [ [/(DENO_VERSION: ").*(")/, DENO_VERSION], ], - "./host/mod.ts": [ - [/(GHJK_VERSION = ").*(")/, GHJK_VERSION], - ], - "./tests/test.Dockerfile": [ - [/(ARG DENO_VERSION=).*()/, DENO_VERSION], - [/(ARG RUST_VERSION=).*()/, RUST_VERSION], - ], "./docs/*.md": [ [ /(.*\/metatypedev\/ghjk\/v)[^/]*(\/.*)/, diff --git a/host/mod.ts b/host/mod.ts deleted file mode 100644 index c4b2315..0000000 --- a/host/mod.ts +++ /dev/null @@ -1,627 +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 { task$ } from "../files/mod.ts"; -import type { ModuleBase } from "../modules/mod.ts"; -import { GhjkCtx } from "../modules/types.ts"; -import { serializePlatform } from "../modules/ports/types/platform.ts"; -import { default as initTasks } from "./init/mod.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.3.0"; - -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 initCmd = new cliffy_cmd.Command() - .description("Commands for setting up cwd for ghjk.") - .action(function () { - this.showHelp(); - }); - for (const [name, def] of Object.entries(initTasks)) { - initCmd.command( - name.replace("init-", ""), - new cliffy_cmd.Command() - .description(def.desc!) - .useRawArgs() - .action(async (_, ...argv) => { - const env = Deno.env.toObject(); - const workingDir = Deno.cwd(); - const dollar = task$(argv, env, workingDir, name); - await def.fn!(dollar, { argv, workingDir, env, $: dollar }); - }), - ); - } - - const root = new cliffy_cmd.Command() - .name("ghjk") - .version(GHJK_VERSION) - .description("Programmable runtime manager.") - .action(function () { - this.showHelp(); - }) - .command( - "init", - initCmd, - ) - .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 to the dir of the currently active ghjk context.", - ) - .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 and 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), - ); - }), - ), - ) - .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()); - }), - ); - - 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(gcx); - lockEntries[man.id] = await instance.loadLockEntry( - 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][]; - - 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(gcx); - await instance.loadConfig( - man, - configExt.config.blackboard, - lockEntries[man.id], - ); - instances.push([man.id, instance] as const); - for (const [cmdName, cmd] of Object.entries(instance.commands())) { - 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]; - } - } - - // `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], - ) => [id, await instance.genLockEntry()], - ), - ), - ); - // avoid writing lockfile if nothing's changed - if (!lastLockObj || !deep_eql(newLockObj, lastLockObj)) { - lastLockObj = { ...newLockObj }; - await lockFilePath.writeJsonPretty(newLockObj); - } - - // we only write out hashfile when the serialization - // result was saved in the lock file - if ( - !hcx.lockedFlagSet && wasReSerialized && ( - !foundHashObj || !deep_eql(newHashObj, foundHashObj) - ) - ) { - await hashFilePath.writeJsonPretty(newHashObj); - } - }, - }; -} - -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/main.ts b/main.ts deleted file mode 100755 index 35a2f83..0000000 --- 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/modules/envs/mod.ts b/modules/envs/mod.ts index d068c17..996970a 100644 --- a/modules/envs/mod.ts +++ b/modules/envs/mod.ts @@ -179,12 +179,6 @@ export class EnvsModule extends ModuleBase { ? envKeyMaybe[0] : envKeyMaybe) as string, }); - $.dbg("activating env", { - envKey, - envKeyMaybe, - taskKeyMaybe, - envName, - }); await reduceAndCookEnv(gcx, ecx, envKey, envName ?? envKey); }, }, @@ -336,7 +330,6 @@ async function reduceAndCookEnv( const namedDir = $.path(gcx.ghjkDir).join("envs", name); await $.removeIfExists(namedDir); await namedDir.symlinkTo(envDir, { kind: "relative" }); - $.dbg(`linking ${name} to ${envKey}`); } if (name == ecx.config.defaultEnv || key == ecx.config.defaultEnv) { const defaultEnvDir = $.path(gcx.ghjkDir).join("envs", "default"); diff --git a/modules/envs/posix.ts b/modules/envs/posix.ts index e729b0c..e9d0f21 100644 --- a/modules/envs/posix.ts +++ b/modules/envs/posix.ts @@ -201,7 +201,6 @@ async function writeActivators( onEnterHooks: [string, string[]][], onExitHooks: [string, string[]][], ) { - $.dbg("writing activators", { envVars, pathVars, onEnterHooks, onExitHooks }); const ghjkDirVar = "_ghjk_dir"; const shareDirVar = "_ghjk_share_dir"; pathVars = { diff --git a/src/deno_systems/bindings.ts b/src/deno_systems/bindings.ts index 8f2e4ed..84e3021 100644 --- a/src/deno_systems/bindings.ts +++ b/src/deno_systems/bindings.ts @@ -151,7 +151,6 @@ function commandBinding(commandRaw: CliCommand): CliCommandBindedX { `sys_cli_command_action_${command.name}_${actionId}`, async (args) => { const actionArgs = bindingTypes.cliActionArgs.parse(args); - $.dbg("actionArgs", {actionArgs, command}); await action(actionArgs); return {}; }, diff --git a/src/ghjk/ext/callbacks.rs b/src/ghjk/ext/callbacks.rs index 5a8def2..bbcc72a 100644 --- a/src/ghjk/ext/callbacks.rs +++ b/src/ghjk/ext/callbacks.rs @@ -57,13 +57,8 @@ impl CallbackLine { // debug!("callback line was not set, worker callbacks will noop"); return None; } - match self.cx.take() { - Some(val) => Some(val), - None => { - // debug!("realm with callbacks just had a child, it won't inherit callback feature"); - None - } - } + // debug!("realm with callbacks just had a child, it won't inherit callback feature"); + self.cx.take() } } @@ -114,6 +109,10 @@ pub struct Callbacks { /// /// 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 { mut rx, @@ -216,7 +215,7 @@ impl Callbacks { if res.is_promise() { let promise = v8::Local::::try_from(res).unwrap(); - if let None = + let deno_shutting_down = denort::promises::watch_promise(scope, promise, move |scope, _rf, res| { let res = match res { @@ -238,7 +237,8 @@ impl Callbacks { }; tx.send(res).expect_or_log("channel error") }) - { + .is_none(); + if deno_shutting_down { return Err(CallbackError::V8Error(ferr!("js runtime is shutting down"))); }; Ok(None) diff --git a/tests/todo.ts b/tests/todo.ts new file mode 100644 index 0000000..df68f0e --- /dev/null +++ b/tests/todo.ts @@ -0,0 +1,2 @@ +// TODO: tests for hashfile invalidation +// TODO: tests for lockfile impl diff --git a/tests/utils.ts b/tests/utils.ts index ad6084e..6438f32 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -62,7 +62,7 @@ exec ${ghjkExePath.resolve().toString()} "$@"`, // share the system's deno cache GHJK_DENO_DIR: Deno.env.get("DENO_DIR") ?? $.path(Deno.env.get("HOME")!).join(".cache", "deno").toString(), - RUST_LOG: $.dbg(Deno.env.get("RUST_LOG"), "RUST_LOG"), + RUST_LOG: Deno.env.get("RUST_LOG"), GHJK_LOG: Deno.env.get("GHJK_LOG"), ...testEnvs, }; From a9627dcde8820834b4c434498c29b59be4de7eb5 Mon Sep 17 00:00:00 2001 From: Yohe-Am <56622350+Yohe-Am@users.noreply.github.com> Date: Wed, 25 Dec 2024 17:26:24 +0300 Subject: [PATCH 10/13] wip: missing ci dep --- .github/workflows/tests.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 84f6f13..082cdd7 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -9,6 +9,7 @@ on: - ready_for_review env: + DENO_VERSION: "2.1.2" GHJK_LOG: debug GHJK_LOG_PANIC_LEVEL: error DENO_DIR: .deno-dir @@ -27,6 +28,9 @@ jobs: steps: - uses: actions/checkout@v4 - uses: dsherret/rust-toolchain-file@v1 + - uses: denoland/setup-deno@v1 + with: + deno-version: ${{ env.DENO_VERSION }} # run ghjk once to avoid trigger file changes when # pre commit runs ghjk. We'll always see changes # to lock.json since GITHUB_TOKEN is different @@ -54,6 +58,9 @@ jobs: steps: - uses: actions/checkout@v4 - uses: dsherret/rust-toolchain-file@v1 + - uses: denoland/setup-deno@v1 + with: + deno-version: ${{ env.DENO_VERSION }} - name: Cache deno dir uses: actions/cache@v4 with: From a59218807f78bc36205ada925b03e4018f0fc1d5 Mon Sep 17 00:00:00 2001 From: Yohe-Am <56622350+Yohe-Am@users.noreply.github.com> Date: Wed, 25 Dec 2024 17:58:07 +0300 Subject: [PATCH 11/13] wip: error in path absolutsizing --- .github/workflows/tests.yml | 16 ++++++++++++---- src/ghjk/config.rs | 19 ++++++++++--------- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 082cdd7..a29181f 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,6 +10,10 @@ on: - synchronize - ready_for_review +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + env: DENO_VERSION: "2.1.2" GHJK_LOG: debug @@ -67,13 +73,15 @@ jobs: path: ${{ env.DENO_DIR }} 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: | - # 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 + # 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: diff --git a/src/ghjk/config.rs b/src/ghjk/config.rs index d5f937f..5157c90 100644 --- a/src/ghjk/config.rs +++ b/src/ghjk/config.rs @@ -30,14 +30,14 @@ impl Config { 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").await? { + 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").await? { + let ghjkfile_path = match path_from_env(&cwd, "GHJKFILE")? { Some(val) => Some(val), None => { // NOTE: look for typescript ghjkfile @@ -102,7 +102,7 @@ impl Config { }, }; - let global_config_path = match path_from_env(&cwd, "GHJK_CONFIG_DIR").await? { + let global_config_path = match path_from_env(&cwd, "GHJK_CONFIG_DIR")? { Some(val) => val, None => xdg_dirs.config_dir().join("config"), }; @@ -262,12 +262,12 @@ hash.json", fn resolve_config_path(path: impl AsRef, config_path: &Path) -> Res { let path = config_path.join(&path); - let path = std::fs::canonicalize(&path) - .wrap_err_with(|| format!("error canonicalizing path at {path:?}"))?; + let path = std::path::absolute(&path) + .wrap_err_with(|| format!("error absolutizing path at {path:?}"))?; Ok(path) } -async fn path_from_env(cwd: &Path, env_name: &str) -> Res> { +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)), @@ -276,9 +276,10 @@ async fn path_from_env(cwd: &Path, env_name: &str) -> Res> { if let Some(path) = path { let path = cwd.join(&path); - Ok(Some(tokio::fs::canonicalize(&path).await.wrap_err_with( - || format!("error canonicalizing path {path:?} from env ${env_name}"), - )?)) + + Ok(Some(std::path::absolute(&path).wrap_err_with(|| { + format!("error absolutizing path {path:?} from env ${env_name}") + })?)) } else { Ok(None) } From 572c74bec0f56ada7a6accc634f46daaaef38bd9 Mon Sep 17 00:00:00 2001 From: Yohe-Am <56622350+Yohe-Am@users.noreply.github.com> Date: Wed, 25 Dec 2024 21:51:40 +0300 Subject: [PATCH 12/13] wip: rustflag to all targets --- .cargo/config.toml | 2 +- .github/workflows/tests.yml | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 05dde38..53a1c12 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -2,7 +2,7 @@ xtask = "run --package xtask --" x = "run --package xtask --" -[target.x86_64-unknown-linux-gnu] +[build] rustflags = [ # for use with tokio-rs/console "--cfg", diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a29181f..2860abc 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -30,6 +30,7 @@ jobs: - uses: actions/checkout@v4 test-pre-commit: + timeout-minutes: 15 runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -47,6 +48,7 @@ jobs: SKIP: ghjk-resolve test-e2e: + timeout-minutes: 60 runs-on: "${{ matrix.os }}" strategy: fail-fast: false From fa9a7a86efccdbe75b7a3452487866c147cfdeed Mon Sep 17 00:00:00 2001 From: Yohe-Am <56622350+Yohe-Am@users.noreply.github.com> Date: Sat, 28 Dec 2024 10:10:36 +0100 Subject: [PATCH 13/13] fix: fix second deadlock bug --- .ghjk/lock.json | 26 +++++++++++++------------- .pre-commit-config.yaml | 1 - ghjk.ts | 27 +++++++++++++++++++++++++-- src/denort/worker.rs | 9 +++++---- src/ghjk/cli.rs | 9 +++++++++ src/ghjk/host/hashfile.rs | 21 +++++++++++++++++++-- src/ghjk/log.rs | 8 +++++--- 7 files changed, 76 insertions(+), 25 deletions(-) diff --git a/.ghjk/lock.json b/.ghjk/lock.json index 1628909..7411cce 100644 --- a/.ghjk/lock.json +++ b/.ghjk/lock.json @@ -380,7 +380,7 @@ "lock-sed": { "ty": "denoFile@v1", "key": "lock-sed", - "envKey": "bciqbs6giotedkicnvrztzwovfr4siq2phoa63wngljmzna6aa4kyciy" + "envKey": "bciqocjamyeiuh6llwcdqg4q4ceantuzpbm5bmnlz7pkqz4r2ca7w2eq" }, "cache-v8": { "ty": "denoFile@v1", @@ -407,13 +407,13 @@ } ] }, - "bciqonpyvifzte5gf6tl7gtk3ep5q3vst2gqncuznf3kav4mzbuvnpai": { + "bciqfnku2tswsz4gapwhys5ox5uiyzcb5r7bmuwzljjeziljcu7efroi": { "desc": "the default default environment.", "provides": [ { "ty": "posix.envVar", "key": "RUST_LOG", - "val": "info,deno=info,denort=trace,swc_ecma_transforms_base=info,swc_common=info,h2=info,rustls=info,mio=info,hyper_util=info" + "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", @@ -421,12 +421,12 @@ } ] }, - "bciqbs6giotedkicnvrztzwovfr4siq2phoa63wngljmzna6aa4kyciy": { + "bciqocjamyeiuh6llwcdqg4q4ceantuzpbm5bmnlz7pkqz4r2ca7w2eq": { "provides": [ { "ty": "posix.envVar", "key": "RUST_LOG", - "val": "info,deno=info,denort=trace,swc_ecma_transforms_base=info,swc_common=info,h2=info,rustls=info,mio=info,hyper_util=info" + "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", @@ -434,12 +434,12 @@ } ] }, - "bciqm4lt7lvjdt3qzudw24qe4brezcej3ilxxhbmgfo2gdbfmh4j3a7i": { + "bciqex5g2cetqvfipwhu6fb3mmyke3y6jvrscjrykf2zl7wfwupiqhca": { "provides": [ { "ty": "posix.envVar", "key": "RUST_LOG", - "val": "info,deno=info,denort=trace,swc_ecma_transforms_base=info,swc_common=info,h2=info,rustls=info,mio=info,hyper_util=info" + "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", @@ -447,17 +447,17 @@ } ] }, - "bciqkyp5qbfd3frv2e5hou4mgrlcodb5eaidc43el63bonty4i3thlya": { + "bciqnerbswitlqt27ado74puxt3faxea6jaxe4wvytnzwjpupig25kky": { "provides": [ { "ty": "posix.envVar", "key": "RUST_LOG", - "val": "info,deno=info,denort=trace,swc_ecma_transforms_base=info,swc_common=info,h2=info,rustls=info,mio=info,hyper_util=info" + "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" + "val": "/home/yohe/ghjk/.dev/rusty_v8" }, { "ty": "ghjk.ports.InstallSetRef", @@ -468,9 +468,9 @@ }, "defaultEnv": "dev", "envsNamed": { - "main": "bciqonpyvifzte5gf6tl7gtk3ep5q3vst2gqncuznf3kav4mzbuvnpai", - "_rust": "bciqm4lt7lvjdt3qzudw24qe4brezcej3ilxxhbmgfo2gdbfmh4j3a7i", - "dev": "bciqkyp5qbfd3frv2e5hou4mgrlcodb5eaidc43el63bonty4i3thlya" + "main": "bciqfnku2tswsz4gapwhys5ox5uiyzcb5r7bmuwzljjeziljcu7efroi", + "_rust": "bciqex5g2cetqvfipwhu6fb3mmyke3y6jvrscjrykf2zl7wfwupiqhca", + "dev": "bciqnerbswitlqt27ado74puxt3faxea6jaxe4wvytnzwjpupig25kky" } } } diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f92f43a..a0766cc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -70,7 +70,6 @@ repos: rev: v1.0 hooks: - id: fmt - exclude: tests/metagen/typegraphs/sample/rs/client.rs - id: clippy args: - "--locked" diff --git a/ghjk.ts b/ghjk.ts index 79f2e7a..4df7b51 100644 --- a/ghjk.ts +++ b/ghjk.ts @@ -26,8 +26,31 @@ config({ }); env("main").vars({ - RUST_LOG: - "info,deno=info,denort=trace,swc_ecma_transforms_base=info,swc_common=info,h2=info,rustls=info,mio=info,hyper_util=info", + 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") diff --git a/src/denort/worker.rs b/src/denort/worker.rs index 08c4b5b..9a36e4c 100644 --- a/src/denort/worker.rs +++ b/src/denort/worker.rs @@ -393,8 +393,12 @@ impl ModuleWorkerContext { .await?; } */ - let event_loop_future = self.worker.run_event_loop(false).boxed_local(); + 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"); @@ -408,9 +412,6 @@ impl ModuleWorkerContext { event_loop_result? } }; - self.worker - .run_event_loop(self.maybe_coverage_collector.is_none()) - .await?; let web_continue = self.worker.dispatch_beforeunload_event()?; if !web_continue { diff --git a/src/ghjk/cli.rs b/src/ghjk/cli.rs index f4c08ca..90d43e1 100644 --- a/src/ghjk/cli.rs +++ b/src/ghjk/cli.rs @@ -11,6 +11,15 @@ 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?; diff --git a/src/ghjk/host/hashfile.rs b/src/ghjk/host/hashfile.rs index 038c9e8..be4d03e 100644 --- a/src/ghjk/host/hashfile.rs +++ b/src/ghjk/host/hashfile.rs @@ -130,7 +130,24 @@ async fn file_digests( hcx: &HostCtx, read_files: Vec<&Path>, ) -> Res>> { - let out = read_files + futures::future::join_all( + read_files + .into_iter() + .map(|path| { + async move { + let path = tokio::fs::canonicalize(path).await?; + let hash = file_digest_hash(hcx, &path).await?; + let relative_path = pathdiff::diff_paths(path, &hcx.config.cwd).unwrap(); + Ok((relative_path, hash)) + } + .boxed() + }) + .collect::>(), + ) + .await + .into_iter() + .collect() + /* let out = read_files .into_co_stream() .map(|path| async move { let path = tokio::fs::canonicalize(path).await?; @@ -140,7 +157,7 @@ async fn file_digests( }) .collect::>>() .await?; - Ok(out.into_iter().collect()) + Ok(out.into_iter().collect()) */ } pub async fn file_digest_hash(hcx: &HostCtx, path: &Path) -> Res> { diff --git a/src/ghjk/log.rs b/src/ghjk/log.rs index cc0505f..28325d7 100644 --- a/src/ghjk/log.rs +++ b/src/ghjk/log.rs @@ -86,16 +86,18 @@ Args: {args:?} 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()); - registry + 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()) - .init(); + .with(tracing_error::ErrorLayer::default()); + + registry.init(); // console_subscriber::init(); }); }