From 550468861bf26cc74752850a6cb3d38eea1e4d6a Mon Sep 17 00:00:00 2001 From: Yohe-Am <56622350+Yohe-Am@users.noreply.github.com> Date: Sat, 4 Jan 2025 05:02:21 +0300 Subject: [PATCH] wip!: breaking warts --- .ghjk/lock.json | 212 +++++++++++++++++++--------- .github/actionlint.yaml | 2 + .github/workflows/tests.yml | 2 +- .pre-commit-config.yaml | 4 +- README.md | 10 +- deno.jsonc | 2 +- docs/manual.md | 13 +- examples/env_vars/ghjk.ts | 3 +- examples/envs/ghjk.ts | 2 +- examples/kitchen/ghjk.ts | 10 +- examples/many_installs/ghjk.ts | 2 +- examples/tasks/ghjk.ts | 2 +- {host/init => examples}/template.ts | 12 +- files/deno/bindings.ts | 10 +- files/deno/worker.ts | 49 ------- files/mod.ts | 2 +- files/types.ts | 15 ++ ghjk.ts | 115 +++++++-------- hack.ts | 4 +- host/init/mod.ts | 10 +- host/types.ts | 22 --- mod.ts | 10 +- modules/envs/mod.ts | 17 ++- modules/mod.ts | 5 +- modules/ports/mod.ts | 2 +- modules/ports/types.ts | 2 +- modules/tasks/deno.ts | 2 +- modules/tasks/mod.ts | 3 +- modules/tasks/types.ts | 2 +- modules/types.ts | 8 ++ ports/cargobi.ts | 7 + ports/npmi.ts | 4 +- src/deno_systems/bindings.ts | 11 +- src/deno_systems/types.ts | 70 ++++----- src/ghjk/cli.rs | 101 +++++++++++-- src/ghjk/config.rs | 4 +- src/ghjk/host.rs | 2 +- src/ghjk/host/hashfile.rs | 11 +- src/ghjk/log.rs | 4 +- src/ghjk/main.rs | 18 ++- src/ghjk/systems/deno.rs | 3 + src/ghjk/utils.rs | 12 ++ tests/envHooks.ts | 2 +- tests/examples.ts | 28 ++++ tests/hashfile.ts | 11 +- tests/tasks.ts | 5 +- tests/utils.ts | 6 +- tools/dev.ts | 2 +- utils/mod.ts | 2 +- 49 files changed, 527 insertions(+), 330 deletions(-) create mode 100644 .github/actionlint.yaml rename {host/init => examples}/template.ts (51%) delete mode 100644 files/deno/worker.ts create mode 100644 files/types.ts delete mode 100644 host/types.ts create mode 100644 tests/examples.ts diff --git a/.ghjk/lock.json b/.ghjk/lock.json index b1faf95..0d51003 100644 --- a/.ghjk/lock.json +++ b/.ghjk/lock.json @@ -295,6 +295,44 @@ "portRef": "asdf_plugin_git@0.1.0", "pluginRepo": "https://github.com/lsanwick/asdf-jq", "specifiedVersion": false + }, + "bciqjtrxihpi27npax5rsw7dgpojy6gkpo7vwhb2opxobk24mbgmcp7q": { + "version": "0.12.1", + "buildDepConfigs": { + "cargo_binstall_ghrel": { + "version": "v1.10.18", + "buildDepConfigs": {}, + "portRef": "cargo_binstall_ghrel@0.1.0", + "specifiedVersion": false + }, + "rust_rustup": { + "version": "1.82.0", + "buildDepConfigs": { + "rustup_rustlang": { + "version": "1.27.1", + "buildDepConfigs": { + "git_aa": { + "version": "2.47.1", + "buildDepConfigs": {}, + "portRef": "git_aa@0.1.0", + "specifiedVersion": false + } + }, + "portRef": "rustup_rustlang@0.1.0", + "specifiedVersion": false + } + }, + "portRef": "rust_rustup@0.1.0", + "profile": "default", + "components": [ + "rust-src" + ], + "specifiedVersion": true + } + }, + "portRef": "cargobi_cratesio@0.1.0", + "crateName": "cargo-bloat", + "specifiedVersion": false } } }, @@ -313,11 +351,11 @@ "sets": { "ghjkEnvProvInstSet___main": { "installs": [ - "bciqjucge6yrzcawqzcljvrpmtwrocecsww6pcjwipzn5j2hfwjof7za", "bciqe72molvtvcuj3tuh47ziue2oqd6t4qetxn3rsoa764ofup6uwjmi", "bciqe4zlekl4uqqbhxunac7br24mrf6cdpfrfblahqa4vrgaqjujcl4i", "bciqpu4klxr3hl6ujhmflrlfd3dxp47ijq26mnathb26ojzwkeggy5ii", - "bciqelae2kzmf7umbo62flzq2mnlhnc4ilbfmn4va2fzrqwx7w7zusji" + "bciqelae2kzmf7umbo62flzq2mnlhnc4ilbfmn4va2fzrqwx7w7zusji", + "bciqjucge6yrzcawqzcljvrpmtwrocecsww6pcjwipzn5j2hfwjof7za" ], "allowedBuildDeps": "bciqdg64uhkvlkqyc7nli33cja3aolbcdr75qepnrhj5ojlifsvxqzgq" }, @@ -326,26 +364,28 @@ "bciqikjfnbntvagpghawbzlfp2es6lnqzhba3qx5de7tdrmvhuzhsjqa", "bciqfrfun7z7soj7yxzziyvmt2jnebqvneeoozk5vynmg5pa6wqynhvi", "bciqgkc6fegmxehj4whmusfuurxyp4ayeysn6qa2t6q64baac5is7uui", - "bciqjucge6yrzcawqzcljvrpmtwrocecsww6pcjwipzn5j2hfwjof7za", + "bciqlmoqot4jk2lb2b34pldr5iiwsfm3biuipzesjkkwmc2n2o6nlw4q", "bciqe72molvtvcuj3tuh47ziue2oqd6t4qetxn3rsoa764ofup6uwjmi", "bciqe4zlekl4uqqbhxunac7br24mrf6cdpfrfblahqa4vrgaqjujcl4i", "bciqpu4klxr3hl6ujhmflrlfd3dxp47ijq26mnathb26ojzwkeggy5ii", - "bciqelae2kzmf7umbo62flzq2mnlhnc4ilbfmn4va2fzrqwx7w7zusji" + "bciqelae2kzmf7umbo62flzq2mnlhnc4ilbfmn4va2fzrqwx7w7zusji", + "bciqjucge6yrzcawqzcljvrpmtwrocecsww6pcjwipzn5j2hfwjof7za" ], "allowedBuildDeps": "bciqdg64uhkvlkqyc7nli33cja3aolbcdr75qepnrhj5ojlifsvxqzgq" }, "ghjkEnvProvInstSet___dev": { "installs": [ "bciqlfx3mm5hi37g75snjknph6fkniixjhnvyyfxeua7f5z4h7nnqtna", - "bciqlmoqot4jk2lb2b34pldr5iiwsfm3biuipzesjkkwmc2n2o6nlw4q", + "bciqhsrsmayibhhhcp3jmay4tnrsyhz5od6ngtaazymx3o64xxzbqiha", "bciqikjfnbntvagpghawbzlfp2es6lnqzhba3qx5de7tdrmvhuzhsjqa", "bciqfrfun7z7soj7yxzziyvmt2jnebqvneeoozk5vynmg5pa6wqynhvi", "bciqgkc6fegmxehj4whmusfuurxyp4ayeysn6qa2t6q64baac5is7uui", - "bciqjucge6yrzcawqzcljvrpmtwrocecsww6pcjwipzn5j2hfwjof7za", + "bciqlmoqot4jk2lb2b34pldr5iiwsfm3biuipzesjkkwmc2n2o6nlw4q", "bciqe72molvtvcuj3tuh47ziue2oqd6t4qetxn3rsoa764ofup6uwjmi", "bciqe4zlekl4uqqbhxunac7br24mrf6cdpfrfblahqa4vrgaqjujcl4i", "bciqpu4klxr3hl6ujhmflrlfd3dxp47ijq26mnathb26ojzwkeggy5ii", - "bciqelae2kzmf7umbo62flzq2mnlhnc4ilbfmn4va2fzrqwx7w7zusji" + "bciqelae2kzmf7umbo62flzq2mnlhnc4ilbfmn4va2fzrqwx7w7zusji", + "bciqjucge6yrzcawqzcljvrpmtwrocecsww6pcjwipzn5j2hfwjof7za" ], "allowedBuildDeps": "bciqdg64uhkvlkqyc7nli33cja3aolbcdr75qepnrhj5ojlifsvxqzgq" }, @@ -430,7 +470,7 @@ } ] }, - "bciqnerbswitlqt27ado74puxt3faxea6jaxe4wvytnzwjpupig25kky": { + "bciqgcwltl3sbuyrqlhxz2spihe2asdzrgt3axosw3mre7ived23syhy": { "provides": [ { "ty": "posix.envVar", @@ -440,7 +480,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", @@ -453,62 +493,13 @@ "envsNamed": { "main": "bciqfnku2tswsz4gapwhys5ox5uiyzcb5r7bmuwzljjeziljcu7efroi", "_rust": "bciqex5g2cetqvfipwhu6fb3mmyke3y6jvrscjrykf2zl7wfwupiqhca", - "dev": "bciqnerbswitlqt27ado74puxt3faxea6jaxe4wvytnzwjpupig25kky" + "ci": "bciqex5g2cetqvfipwhu6fb3mmyke3y6jvrscjrykf2zl7wfwupiqhca", + "dev": "bciqgcwltl3sbuyrqlhxz2spihe2asdzrgt3axosw3mre7ived23syhy" } } } ], "blackboard": { - "bciqjucge6yrzcawqzcljvrpmtwrocecsww6pcjwipzn5j2hfwjof7za": { - "buildDepConfigs": { - "asdf_plugin_git": { - "pluginRepo": "https://github.com/lsanwick/asdf-jq", - "portRef": "asdf_plugin_git@0.1.0" - } - }, - "resolutionDepConfigs": { - "asdf_plugin_git": { - "pluginRepo": "https://github.com/lsanwick/asdf-jq", - "portRef": "asdf_plugin_git@0.1.0" - } - }, - "port": { - "ty": "denoWorker@v1", - "name": "asdf", - "platforms": [ - "x86_64-linux", - "aarch64-linux", - "x86_64-darwin", - "aarch64-darwin" - ], - "version": "0.1.0", - "buildDeps": [ - { - "name": "curl_aa" - }, - { - "name": "git_aa" - }, - { - "name": "asdf_plugin_git" - } - ], - "resolutionDeps": [ - { - "name": "curl_aa" - }, - { - "name": "git_aa" - }, - { - "name": "asdf_plugin_git" - } - ], - "moduleSpecifier": "file:///ports/asdf.ts" - }, - "pluginRepo": "https://github.com/lsanwick/asdf-jq", - "installType": "version" - }, "bciqe72molvtvcuj3tuh47ziue2oqd6t4qetxn3rsoa764ofup6uwjmi": { "port": { "ty": "denoWorker@v1", @@ -610,6 +601,56 @@ "moduleSpecifier": "file:///ports/deno_ghrel.ts" } }, + "bciqjucge6yrzcawqzcljvrpmtwrocecsww6pcjwipzn5j2hfwjof7za": { + "buildDepConfigs": { + "asdf_plugin_git": { + "pluginRepo": "https://github.com/lsanwick/asdf-jq", + "portRef": "asdf_plugin_git@0.1.0" + } + }, + "resolutionDepConfigs": { + "asdf_plugin_git": { + "pluginRepo": "https://github.com/lsanwick/asdf-jq", + "portRef": "asdf_plugin_git@0.1.0" + } + }, + "port": { + "ty": "denoWorker@v1", + "name": "asdf", + "platforms": [ + "x86_64-linux", + "aarch64-linux", + "x86_64-darwin", + "aarch64-darwin" + ], + "version": "0.1.0", + "buildDeps": [ + { + "name": "curl_aa" + }, + { + "name": "git_aa" + }, + { + "name": "asdf_plugin_git" + } + ], + "resolutionDeps": [ + { + "name": "curl_aa" + }, + { + "name": "git_aa" + }, + { + "name": "asdf_plugin_git" + } + ], + "moduleSpecifier": "file:///ports/asdf.ts" + }, + "pluginRepo": "https://github.com/lsanwick/asdf-jq", + "installType": "version" + }, "bciqdfarczmlu3r5dkvcdoultfbnuvn6saao55h4fbb3jg72kv6mkr3y": { "manifest": { "ty": "denoWorker@v1", @@ -1009,6 +1050,25 @@ "rust-src" ] }, + "bciqlmoqot4jk2lb2b34pldr5iiwsfm3biuipzesjkkwmc2n2o6nlw4q": { + "version": "v2.4.0", + "port": { + "ty": "denoWorker@v1", + "name": "mold_ghrel", + "platforms": [ + "aarch64-linux", + "x86_64-linux" + ], + "version": "0.1.0", + "buildDeps": [ + { + "name": "tar_aa" + } + ], + "moduleSpecifier": "file:///ports/mold.ts" + }, + "replaceLd": true + }, "bciqlfx3mm5hi37g75snjknph6fkniixjhnvyyfxeua7f5z4h7nnqtna": { "port": { "ty": "denoWorker@v1", @@ -1046,24 +1106,42 @@ }, "crateName": "tokio-console" }, - "bciqlmoqot4jk2lb2b34pldr5iiwsfm3biuipzesjkkwmc2n2o6nlw4q": { - "version": "v2.4.0", + "bciqhsrsmayibhhhcp3jmay4tnrsyhz5od6ngtaazymx3o64xxzbqiha": { "port": { "ty": "denoWorker@v1", - "name": "mold_ghrel", + "name": "cargobi_cratesio", "platforms": [ + "x86_64-linux", "aarch64-linux", - "x86_64-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": "tar_aa" + "name": "cargo_binstall_ghrel" + }, + { + "name": "rust_rustup" } ], - "moduleSpecifier": "file:///ports/mold.ts" + "moduleSpecifier": "file:///ports/cargobi.ts" }, - "replaceLd": true + "crateName": "cargo-bloat" }, "bciqeie3punk3gz4kcfdk2fxx5bsj5fh3j7bb7z36qmimayhwdsvp7cq": {} } diff --git a/.github/actionlint.yaml b/.github/actionlint.yaml new file mode 100644 index 0000000..2cc072f --- /dev/null +++ b/.github/actionlint.yaml @@ -0,0 +1,2 @@ +runner-labels: + - custom-arm diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1517cff..9b2a08b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -42,7 +42,7 @@ jobs: # pre commit runs ghjk. We'll always see changes # to lock.json since GITHUB_TOKEN is different # in the CI - - run: deno task self envs cook -t lock-sed + - run: deno task ghjk envs cook -t lock-sed - uses: pre-commit/action@v3.0.1 env: SKIP: ghjk-resolve diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a0766cc..4f8a3bd 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -38,12 +38,12 @@ repos: - id: ghjk-resolve name: Ghjk resolve language: system - entry: bash -c 'deno task self p resolve' + entry: bash -c 'deno task ghjk p resolve' pass_filenames: false - id: lock-sed name: Sed lock language: system - entry: bash -c 'deno task self x lock-sed' + entry: bash -c 'deno task ghjk x lock-sed' pass_filenames: false - id: deno-fmt name: Deno format diff --git a/README.md b/README.md index c5f884f..d82d8af 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ Before anything, make sure the following programs are available on the system. Install the ghjk cli using the installer scripts like so: ```bash -curl -fsSL https://raw.github.com/metatypedev/ghjk/v0.3.0-rc.1/install.sh | bash +curl -fsSL "https://raw.github.com/metatypedev/ghjk/v0.3.0-rc.1/install.sh" | bash ``` Use the following command to create a starter `ghjk.ts` in your project directory: @@ -65,12 +65,8 @@ import { file } from "https://raw.github.com/metatypedev/ghjk/v0.3.0-rc.1/mod.ts // ports are small programs that install sowtware to your envs import * as ports from "https://raw.github.com/metatypedev/ghjk/v0.3.0-rc.1/ports/mod.ts"; -const ghjk = file({}); - -// NOTE: `ghjk.ts` files are expected to export this sophon object -// all the functions on the ghjk object are ultimately modifying the 'sophon' proxy -// object exported here. -export const sophon = ghjk.sophon; +// NOTE: `ghjk.ts` files are expected to export this ghjk object +export const ghjk = file({}); // top level `install`s go to the `main` env ghjk.install(ports.protoc()); diff --git a/deno.jsonc b/deno.jsonc index 2dfa2c4..dcd1517 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -2,7 +2,7 @@ "tasks": { "test": "cargo build -p ghjk && deno test --unstable-worker-options --unstable-kv -A tests/*", "test-doc": "cargo build -p ghjk && deno test --unstable-worker-options --unstable-kv -A --doc **/*.ts", - "self": "cargo run -p ghjk", + "ghjk": "cargo run -p ghjk", "cache": "deno cache deps/*", "check": "deno run -A ./tools/check.ts", "dev": "deno run -A ./tools/dev.ts" diff --git a/docs/manual.md b/docs/manual.md index f4dedf3..2f09699 100644 --- a/docs/manual.md +++ b/docs/manual.md @@ -17,7 +17,7 @@ There are installer scripts available in the repo. ```bash # stable -curl -fsSL https://raw.github.com/metatypedev/ghjk/v0.3.0-rc.1/install.sh | bash +curl -fsSL "https://raw.github.com/metatypedev/ghjk/v0.3.0-rc.1/install.sh" | bash ``` This will install the CLI and add configuration your shell rc files the necessary hooks ghjk needs to function. @@ -44,11 +44,8 @@ import { file } from ".../mod.ts"; // import the port for the node program import node from ".../ports/node.ts"; -const ghjk = file(); - -// all ghjk.ts files are expected to export this special `sophon` object -// all the functions from the ghjk object are modifying the sophon -export const sophon = ghjk.sophon; +// all ghjk.ts files are expected to export this special `ghjk` object +export const ghjk = file(); // install programs (ports) into your env ghjk.install( @@ -95,7 +92,7 @@ To look at what the ghjkfile looks like serialized, you can use the following co ```bash # look at the serialized form the ghjkfile -ghjk print config +ghjk print serialized ``` #### The Hashfile @@ -414,7 +411,7 @@ Namely, it's good practice to: # sample of how one would install ghjk for use in a Dockerfile ARG GHJK_VERSION=v0.3.0-rc.1 # /usr/bin is available in $PATH by default making ghjk immediately avail -RUN curl -fsSL https://raw.github.com/metatypedev/ghjk/$GHJK_VERSION/install.sh \ +RUN curl -fsSL "https://raw.github.com/metatypedev/ghjk/$GHJK_VERSION/install.sh" \ | GHJK_INSTALL_EXE_DIR=/usr/bin sh ``` diff --git a/examples/env_vars/ghjk.ts b/examples/env_vars/ghjk.ts index 1d98f92..bd9cad0 100644 --- a/examples/env_vars/ghjk.ts +++ b/examples/env_vars/ghjk.ts @@ -1,6 +1,6 @@ import { file } from "../../hack.ts"; -const ghjk = file({ +export const ghjk = file({ defaultEnv: "empty", envs: [{ name: "empty", inherit: false }], defaultBaseEnv: "empty", @@ -11,7 +11,6 @@ const ghjk = file({ tasks: {}, }); -export const sophon = ghjk.sophon; const { env, task } = ghjk; env("main") diff --git a/examples/envs/ghjk.ts b/examples/envs/ghjk.ts index 3a2e7c5..ffb646e 100644 --- a/examples/envs/ghjk.ts +++ b/examples/envs/ghjk.ts @@ -1,4 +1,4 @@ -export { sophon } from "../../hack.ts"; +export { ghjk } from "../../hack.ts"; import { config, env, install, task } from "../../hack.ts"; import * as ports from "../../ports/mod.ts"; diff --git a/examples/kitchen/ghjk.ts b/examples/kitchen/ghjk.ts index ca2aa82..3147abe 100644 --- a/examples/kitchen/ghjk.ts +++ b/examples/kitchen/ghjk.ts @@ -2,7 +2,10 @@ import { stdDeps } from "../../files/mod.ts"; import { file } from "../../mod.ts"; import * as ports from "../../ports/mod.ts"; -const ghjk = file({ +// we need this export for this file to be a valid ghjkfile +// it's the one thing used by the ghjk host implementation to +// interact with your ghjkfile +export const ghjk = file({ // configre an empty env so that no ports are avail by default in our workdir defaultEnv: "empty", envs: [{ name: "empty", inherit: false }], @@ -19,11 +22,6 @@ const ghjk = file({ tasks: {}, }); -// we need this export for this file to be a valid ghjkfile -// it's the one thing used by the ghjk host implementation to -// interact with your ghjkfile -export const sophon = ghjk.sophon; - const { install, env, task } = ghjk; // we can configure main like this as well diff --git a/examples/many_installs/ghjk.ts b/examples/many_installs/ghjk.ts index b5a3a15..60f7986 100644 --- a/examples/many_installs/ghjk.ts +++ b/examples/many_installs/ghjk.ts @@ -1,4 +1,4 @@ -export { sophon } from "../../hack.ts"; +export { ghjk } from "../../hack.ts"; import { config, install } from "../../hack.ts"; import * as ports from "../../ports/mod.ts"; diff --git a/examples/tasks/ghjk.ts b/examples/tasks/ghjk.ts index 61b227f..20eb53b 100644 --- a/examples/tasks/ghjk.ts +++ b/examples/tasks/ghjk.ts @@ -1,4 +1,4 @@ -export { sophon } from "../../hack.ts"; +export { ghjk } from "../../hack.ts"; import { logger, task } from "../../hack.ts"; import * as ports from "../../ports/mod.ts"; diff --git a/host/init/template.ts b/examples/template.ts similarity index 51% rename from host/init/template.ts rename to examples/template.ts index fdf1460..5f53f88 100644 --- a/host/init/template.ts +++ b/examples/template.ts @@ -1,20 +1,18 @@ // @ts-nocheck: Deno based -import { file } from "../../mod.ts"; // template-import -// import * as ports from "../../ports/mod.ts"; // template-import +import { file } from "../mod.ts"; // template-import +// import * as ports from "../ports/mod.ts"; // template-import -const ghjk = file({ +// This export is necessary for typescript ghjkfiles +export const ghjk = file({ // allows usage of ports that depend on node/python // enableRuntimes: true, }); -// This export is necessary for ts ghjkfiles -export const sophon = ghjk.sophon; - ghjk.install( // install ports into the main env // ports.node(), - // ports.cpy_bs(), + // ports.pnpm(), ); ghjk.task("greet", async ($) => { diff --git a/files/deno/bindings.ts b/files/deno/bindings.ts index 8bf47f1..530b57c 100644 --- a/files/deno/bindings.ts +++ b/files/deno/bindings.ts @@ -20,7 +20,15 @@ async function serialize(args: zod.infer) { const { setup: setupLogger } = await import("../../utils/logger.ts"); setupLogger(); const mod = await import(args.uri); - const rawConfig = await mod.sophon.getConfig(args.uri, mod.secureConfig); + if (!mod.ghjk) { + throw new Error(`ghjk.ts does not export a ghjk object: ${args.uri}`); + } + if (!mod.ghjk.sophon) { + throw new Error( + `no sophon found on exported ghjk object from ghjk.ts: ${args.uri}`, + ); + } + const rawConfig = await mod.ghjk.sophon.getConfig(args.uri, mod.secureConfig); const config = JSON.parse(JSON.stringify(rawConfig)); return { config, diff --git a/files/deno/worker.ts b/files/deno/worker.ts deleted file mode 100644 index ca55221..0000000 --- a/files/deno/worker.ts +++ /dev/null @@ -1,49 +0,0 @@ -//! this loads the ghjk.ts module and provides a program for it - -//// -/// - -// all imports in here should be dynamic imports as we want to -// modify the Deno namespace before anyone touches it - -import { shimDenoNamespace } from "../../utils/worker.ts"; -// NOTE: only import types -import type { DriverRequests, DriverResponse } from "./mod.ts"; - -self.onmessage = onMsg; - -async function onMsg(msg: MessageEvent) { - const req = msg.data; - if (!req.ty) { - throw new Error(`unrecognized event data`, { - cause: req, - }); - } - let res: DriverResponse; - if (req.ty == "serialize") { - res = { - ty: req.ty, - payload: await serializeConfig(req.uri, req.envVars), - }; - } else { - throw new Error(`unrecognized request type: ${req.ty}`, { - cause: req, - }); - } - self.postMessage(res); -} - -async function serializeConfig(uri: string, envVars: Record) { - const shimHandle = shimDenoNamespace(envVars); - const { setup: setupLogger } = await import("../../utils/logger.ts"); - setupLogger(); - const mod = await import(uri); - const rawConfig = await mod.sophon.getConfig(uri, mod.secureConfig); - const config = JSON.parse(JSON.stringify(rawConfig)); - return { - config, - accessedEnvKeys: shimHandle.getAccessedEnvKeys(), - readFiles: shimHandle.getReadFiles(), - listedFiles: shimHandle.getListedFiles(), - }; -} diff --git a/files/mod.ts b/files/mod.ts index dc30b66..350f31b 100644 --- a/files/mod.ts +++ b/files/mod.ts @@ -27,7 +27,7 @@ import { import * as std_ports from "../modules/ports/std.ts"; import runtime_ports from "../modules/ports/std_runtime.ts"; // host -import type { SerializedConfig } from "../host/types.ts"; +import type { SerializedConfig } from "./types.ts"; import * as std_modules from "../modules/std.ts"; // tasks // WARN: this module has side-effects and only ever import diff --git a/files/types.ts b/files/types.ts new file mode 100644 index 0000000..010baf8 --- /dev/null +++ b/files/types.ts @@ -0,0 +1,15 @@ +import { zod } from "../deps/common.ts"; +import moduleValidators from "../modules/types.ts"; + +const serializedConfig = zod.object( + { + modules: zod.array(moduleValidators.moduleManifest), + blackboard: moduleValidators.blackboard, + }, +); + +export type SerializedConfig = zod.infer; + +export default { + serializedConfig, +}; diff --git a/ghjk.ts b/ghjk.ts index 79e8be0..2b2c5a3 100644 --- a/ghjk.ts +++ b/ghjk.ts @@ -1,17 +1,29 @@ // @ts-nocheck: Ghjkfile based on Deno -export { sophon } from "./hack.ts"; -import { config, env, install, task } from "./hack.ts"; -import { switchMap } from "./port.ts"; +import { file } from "./mod.ts"; + import * as ports from "./ports/mod.ts"; +import { switchMap } from "./port.ts"; import { sedLock } from "./std.ts"; import { downloadFile, DownloadFileArgs } from "./utils/mod.ts"; import { unarchive } from "./utils/unarchive.ts"; import dummy from "./ports/dummy.ts"; +export const ghjk = file({}); + +const DENO_VERSION = "2.1.2"; // keep in sync with the deno repo's ./rust-toolchain.toml const RUST_VERSION = "1.82.0"; +ghjk.env("main") + // these are used for developing ghjk + .install( + ports.act(), + ports.pipi({ packageName: "pre-commit" })[0], + ports.pipi({ packageName: "vale" })[0], + ports.deno_ghrel({ version: DENO_VERSION }), + ); + const installs = { rust: ports.rust({ version: RUST_VERSION, @@ -20,84 +32,75 @@ const installs = { }), }; -config({ +ghjk.config({ defaultEnv: "dev", enableRuntimes: true, allowedBuildDeps: [ports.cpy_bs({ version: "3.13.1" }), installs.rust], }); -env("main").vars({ - RUST_LOG: [ - "info", - Object.entries({ - "TRACE": [ - // "denort", - // "deno", - ], - "DEBUG": [ - // "runtime", - // "tokio", - ], - "INFO": [ - "deno::npm", - "deno::file_fetcher", - "swc_ecma_transforms_base", - "swc_common", - "h2", - "rustls", - "mio", - "hyper_util", - ], - }).flatMap(([level, modules]) => - modules.map((module) => `${module}=${level.toLowerCase()}`) - ), - ].join(), -}); - -env("_rust") +ghjk.env("_rust") .install( ports.protoc(), ports.pipi({ packageName: "cmake" })[0], installs.rust, + ...(Deno.build.os == "linux" && !Deno.env.has("NO_MOLD") + ? [ports.mold({ + version: "v2.4.0", + replaceLd: true, + })] + : []), ); -const RUSTY_V8_MIRROR = `${import.meta.dirname}/.dev/rusty_v8`; - -env("dev") +ghjk.env("dev") .inherit("_rust") .install(ports.cargobi({ crateName: "tokio-console" })) + .install(ports.cargobi({ crateName: "cargo-bloat" })) .vars({ // V8_FORCE_DEBUG: "true", - RUSTY_V8_MIRROR, + RUSTY_V8_MIRROR: `${import.meta.dirname}/.dev/rusty_v8`, }); -if (Deno.build.os == "linux" && !Deno.env.has("NO_MOLD")) { - const mold = ports.mold({ - version: "v2.4.0", - replaceLd: true, - }); - env("dev").install(mold); -} +ghjk.env("ci") + .inherit("_rust"); // these are just for quick testing -install( +ghjk.install( ports.asdf({ pluginRepo: "https://github.com/lsanwick/asdf-jq", installType: "version", }), ); -const DENO_VERSION = "2.1.2"; - -// these are used for developing ghjk -install( - ports.act(), - ports.pipi({ packageName: "pre-commit" })[0], - ports.pipi({ packageName: "vale" })[0], - ports.deno_ghrel({ version: DENO_VERSION }), -); +ghjk.env("main") + .vars({ + RUST_LOG: [ + "info", + Object.entries({ + "TRACE": [ + // "denort", + // "deno", + ], + "DEBUG": [ + // "runtime", + // "tokio", + ], + "INFO": [ + "deno::npm", + "deno::file_fetcher", + "swc_ecma_transforms_base", + "swc_common", + "h2", + "rustls", + "mio", + "hyper_util", + ], + }).flatMap(([level, modules]) => + modules.map((module) => `${module}=${level.toLowerCase()}`) + ), + ].join(), + }); -task( +ghjk.task( "cache-v8", { desc: "Install the V8 builds to a local cache.", @@ -142,7 +145,7 @@ task( }, ); -task( +ghjk.task( "lock-sed", async ($) => { const GHJK_VERSION = "0.3.0-rc.1"; diff --git a/hack.ts b/hack.ts index 3d2ebeb..4b6a948 100644 --- a/hack.ts +++ b/hack.ts @@ -8,9 +8,7 @@ export * from "./mod.ts"; import { file } from "./mod.ts"; import logger from "./utils/logger.ts"; -const ghjk = file(); - -export const sophon = Object.freeze(ghjk.sophon); +export const ghjk = Object.freeze(file()); export const config = Object.freeze(firstCallerCheck(ghjk.config)); export const env = Object.freeze(firstCallerCheck(ghjk.env)); export const install = Object.freeze(firstCallerCheck(ghjk.install)); diff --git a/host/init/mod.ts b/host/init/mod.ts index 510c20a..5f64ae6 100644 --- a/host/init/mod.ts +++ b/host/init/mod.ts @@ -106,12 +106,12 @@ async function handleVscodeSettings( } const schema = zod.object({ - "deno.enablePaths": zod.string().array().optional(), - "deno.disablePaths": zod.string().array().optional(), + "deno.enablePaths": zod.string().array().nullish(), + "deno.disablePaths": zod.string().array().nullish(), deno: zod.object({ - enablePaths: zod.string().array().optional(), - disablePaths: zod.string().array().optional(), - }).passthrough().optional(), + enablePaths: zod.string().array().nullish(), + disablePaths: zod.string().array().nullish(), + }).passthrough().nullish(), }).passthrough(); const originalConfig = await vscodeSettings.readJson() diff --git a/host/types.ts b/host/types.ts deleted file mode 100644 index 68283c8..0000000 --- a/host/types.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { zod } from "../deps/common.ts"; -import moduleValidators from "../modules/types.ts"; - -/* const blackboard = zod.object({ - // installs: zod.record(zod.string(), portsValidator.installConfigFat), - // allowedPortDeps: zod.record(zod.string(), portsValidator.allowedPortDep), -}); */ -const blackboard = zod.record(zod.string(), zod.unknown()); - -const serializedConfig = zod.object( - { - modules: zod.array(moduleValidators.moduleManifest), - blackboard, - }, -); - -export type SerializedConfig = zod.infer; -export type Blackboard = zod.infer; - -export default { - serializedConfig, -}; diff --git a/mod.ts b/mod.ts index 681b237..74a2b43 100644 --- a/mod.ts +++ b/mod.ts @@ -110,17 +110,21 @@ type SecureConfigArgs = Omit< >; type DenoFileKnobs = { + /** + * The sophon is the actual proxy between the host world + * and the ghjkfile world. + */ sophon: Readonly; /** - * {@inheritdoc AddInstall} + * {@inheritDoc AddInstall} */ install: AddInstall; /** - * {@inheritdoc AddTask} + * {@inheritDoc AddTask} */ task: AddTask; /** - * {@inheritdoc AddTasks} + * {@inheritDoc AddTasks} */ tasks: AddTasks; /** diff --git a/modules/envs/mod.ts b/modules/envs/mod.ts index 996970a..c699ecf 100644 --- a/modules/envs/mod.ts +++ b/modules/envs/mod.ts @@ -8,9 +8,8 @@ import type { EnvsModuleConfigX, WellKnownProvision, } from "./types.ts"; -import { type GhjkCtx, type ModuleManifest } from "../types.ts"; +import type { Blackboard, GhjkCtx, ModuleManifest } from "../types.ts"; import { ModuleBase } from "../mod.ts"; -import type { Blackboard } from "../../host/types.ts"; import { cookPosixEnv } from "./posix.ts"; import { getPortsCtx, installGraphToSetMeta } from "../ports/inter.ts"; import type { @@ -212,7 +211,15 @@ export class EnvsModule extends ModuleBase { throw new Error(`no env found under "${envKey}"`); } // deno-lint-ignore no-console - console.log($.inspect(await showableEnv(gcx, env, envKey))); + console.log( + $.inspect( + await showableEnv( + gcx, + env, + ecx.keyToName[envKey] ?? [envKey], + ), + ), + ); }, }, ], @@ -343,7 +350,7 @@ async function reduceAndCookEnv( async function showableEnv( gcx: GhjkCtx, recipe: EnvRecipeX, - envName: string, + envName: string[], ) { const printBag = {} as Record; await using scx = await syncCtxFromGhjk(gcx); @@ -411,7 +418,7 @@ async function showableEnv( return { ...printBag, ...(recipe.desc ? { desc: recipe.desc } : {}), - envName, + envName: envName.length < 2 ? envName[0] : envName, }; } diff --git a/modules/mod.ts b/modules/mod.ts index 210079a..65dc5a8 100644 --- a/modules/mod.ts +++ b/modules/mod.ts @@ -1,7 +1,6 @@ -import { Blackboard } from "../host/types.ts"; -import { CliCommand } from "../src/deno_systems/types.ts"; +import type { CliCommand } from "../src/deno_systems/types.ts"; import type { Json } from "../utils/mod.ts"; -import type { GhjkCtx, ModuleManifest } from "./types.ts"; +import type { Blackboard, GhjkCtx, ModuleManifest } from "./types.ts"; export abstract class ModuleBase { constructor(protected gcx: GhjkCtx) {} diff --git a/modules/ports/mod.ts b/modules/ports/mod.ts index 98f9b7b..d683551 100644 --- a/modules/ports/mod.ts +++ b/modules/ports/mod.ts @@ -28,7 +28,7 @@ import { resolveAndInstall, syncCtxFromGhjk, } from "./sync.ts"; // TODO: rename to install.ts -import type { Blackboard } from "../../host/types.ts"; +import type { Blackboard } from "../types.ts"; import { getProvisionReducerStore } from "../envs/reducer.ts"; import { installSetReducer, installSetRefReducer } from "./reducers.ts"; import type { Provision, ProvisionReducer } from "../envs/types.ts"; diff --git a/modules/ports/types.ts b/modules/ports/types.ts index 249c127..97fa847 100644 --- a/modules/ports/types.ts +++ b/modules/ports/types.ts @@ -118,7 +118,7 @@ const installConfigFat = stdInstallConfigFat; const installConfigResolved = installConfigLite.merge(zod.object({ // NOTE: version is no longer nullish version: zod.string(), - versionSpecified: zod.boolean().optional(), + versionSpecified: zod.boolean().nullish(), // buildDepConfigs: zod.record( // portName, // // FIXME: figure out cyclically putting `installConfigResolved` here diff --git a/modules/tasks/deno.ts b/modules/tasks/deno.ts index 680a43e..0f3bc46 100644 --- a/modules/tasks/deno.ts +++ b/modules/tasks/deno.ts @@ -74,7 +74,7 @@ async function importAndExec( ) { const _shimHandle = shimDenoNamespace(args.envVars); const mod = await import(uri); - const ret = await mod.sophon.execTask(args); + const ret = await mod.ghjk.sophon.execTask(args); return { data: ret, status: true }; } diff --git a/modules/tasks/mod.ts b/modules/tasks/mod.ts index c5349c2..84e4fe3 100644 --- a/modules/tasks/mod.ts +++ b/modules/tasks/mod.ts @@ -5,11 +5,10 @@ import { Json, unwrapZodRes } from "../../utils/mod.ts"; import validators from "./types.ts"; import type { TasksModuleConfigX } from "./types.ts"; -import { type ModuleManifest } from "../types.ts"; +import { Blackboard, type ModuleManifest } from "../types.ts"; import { ModuleBase } from "../mod.ts"; import { buildTaskGraph, execTask, type TaskGraph } from "./exec.ts"; -import { Blackboard } from "../../host/types.ts"; import { getTasksCtx } from "./inter.ts"; import { CliCommand } from "../../src/deno_systems/types.ts"; diff --git a/modules/tasks/types.ts b/modules/tasks/types.ts index 4472aca..35add19 100644 --- a/modules/tasks/types.ts +++ b/modules/tasks/types.ts @@ -13,7 +13,7 @@ const taskDefBase = zod.object({ }); const taskDefFullBase = taskDefBase.merge(zod.object({ - env: envsValidators.envRecipe.optional(), + env: envsValidators.envRecipe.nullish(), })); const taskDefHashedBase = taskDefBase.merge(zod.object({ diff --git a/modules/types.ts b/modules/types.ts index 561fa2b..516cef4 100644 --- a/modules/types.ts +++ b/modules/types.ts @@ -11,6 +11,13 @@ const moduleManifest = zod.object({ config: zod.unknown(), }); +/* const blackboard = zod.object({ + // installs: zod.record(zod.string(), portsValidator.installConfigFat), + // allowedPortDeps: zod.record(zod.string(), portsValidator.allowedPortDep), +}); */ +const blackboard = zod.record(zod.string(), zod.unknown()); + +export type Blackboard = zod.infer; export type ModuleId = zod.infer; export type ModuleManifest = zod.infer; export type GhjkCtx = { @@ -24,4 +31,5 @@ export default { moduleManifest, moduleId, envVarName, + blackboard, }; diff --git a/ports/cargobi.ts b/ports/cargobi.ts index fb3d468..9afa08a 100644 --- a/ports/cargobi.ts +++ b/ports/cargobi.ts @@ -175,6 +175,13 @@ export class Port extends PortBase { } } + await $.co( + (await Array.fromAsync( + $.path(args.tmpDirPath).join("bin").walk({ maxDepth: 0 }), + )) + .map(({ path }) => path.chmod(0o700)), + ); + await std_fs.move( args.tmpDirPath, args.downloadPath, diff --git a/ports/npmi.ts b/ports/npmi.ts index 22b6cce..2a1ed79 100644 --- a/ports/npmi.ts +++ b/ports/npmi.ts @@ -83,8 +83,8 @@ export class Port extends PortBase { override async download(args: DownloadArgs) { const conf = confValidator.parse(args.config); - await $.raw`${ - depExecShimPath(std_ports.node_org, "npm", args.depArts) + await $.raw`${depExecShimPath(std_ports.node_org, "npm", args.depArts) + // provide prefix flat to avoid looking at package.json in parent dirs } install --prefix ${args.tmpDirPath} --no-fund ${conf.packageName}@${args.installVersion}` .cwd(args.tmpDirPath) .env(pathsWithDepArts(args.depArts, args.platform.os)); diff --git a/src/deno_systems/bindings.ts b/src/deno_systems/bindings.ts index d1f58b7..2797664 100644 --- a/src/deno_systems/bindings.ts +++ b/src/deno_systems/bindings.ts @@ -20,9 +20,12 @@ setInterval(() => {/* beat */}, 1000); // import "../../src/ghjk/js/mock.sfx.ts"; import { zod } from "../../deps/common.ts"; import { $, unwrapZodRes } from "../../utils/mod.ts"; -import type { GhjkCtx, ModuleManifest } from "../../modules/types.ts"; +import type { + Blackboard, + GhjkCtx, + ModuleManifest, +} from "../../modules/types.ts"; import type { ModuleBase } from "../../modules/mod.ts"; -import type { Blackboard } from "../../host/types.ts"; import { Ghjk, Json } from "../ghjk/js/runtime.js"; import type { @@ -41,10 +44,10 @@ import bindingTypes from "./types.ts"; const prepareArgs = zod.object({ uri: zod.string(), config: zod.object({ - ghjkfile: zod.string().optional(), + ghjkfile: zod.string().nullish(), ghjkdir: zod.string(), data_dir: zod.string(), - deno_lockfile: zod.string().optional(), + deno_lockfile: zod.string().nullish(), repo_root: zod.string(), deno_dir: zod.string(), }), diff --git a/src/deno_systems/types.ts b/src/deno_systems/types.ts index 85b0e17..796dc68 100644 --- a/src/deno_systems/types.ts +++ b/src/deno_systems/types.ts @@ -9,7 +9,7 @@ const denoSystemsRoot = zod.object({ const charSchema = zod.string().length(1); const cliArg = zod.object({ - value_name: zod.string().optional(), + value_name: zod.string().nullish(), value_hint: zod.enum([ "Unknown", "Other", @@ -24,7 +24,7 @@ const cliArg = zod.object({ "Hostname", "Url", "EmailAddress", - ]).optional(), + ]).nullish(), action: zod.enum([ "Set", @@ -36,45 +36,45 @@ const cliArg = zod.object({ "HelpShort", "HelpLong", "Version", - ]).optional(), + ]).nullish(), - required: zod.boolean().optional(), - global: zod.boolean().optional(), - hide: zod.boolean().optional(), - exclusive: zod.boolean().optional(), - trailing_var_arg: zod.boolean().optional(), + required: zod.boolean().nullish(), + global: zod.boolean().nullish(), + hide: zod.boolean().nullish(), + exclusive: zod.boolean().nullish(), + trailing_var_arg: zod.boolean().nullish(), - env: zod.string().optional(), + env: zod.string().nullish(), - help: zod.string().optional(), - long_help: zod.string().optional(), + help: zod.string().nullish(), + long_help: zod.string().nullish(), }); const cliFlag = cliArg.extend({ - long: zod.string().optional(), - long_aliases: zod.string().array().optional(), - visible_long_aliases: zod.string().array().optional(), + long: zod.string().nullish(), + long_aliases: zod.string().array().nullish(), + visible_long_aliases: zod.string().array().nullish(), - short: charSchema.optional(), - short_aliases: charSchema.array().optional(), - visible_short_aliases: charSchema.array().optional(), + short: charSchema.nullish(), + short_aliases: charSchema.array().nullish(), + visible_short_aliases: charSchema.array().nullish(), }); const cliCommandBase = zod.object({ name: zod.string(), - aliases: zod.string().array().optional(), - visible_aliases: zod.string().array().optional(), + aliases: zod.string().array().nullish(), + visible_aliases: zod.string().array().nullish(), - hide: zod.boolean().optional(), - disable_help_subcommand: zod.boolean().optional(), + hide: zod.boolean().nullish(), + disable_help_subcommand: zod.boolean().nullish(), - about: zod.string().optional(), - before_help: zod.string().optional(), - before_long_help: zod.string().optional(), + about: zod.string().nullish(), + before_help: zod.string().nullish(), + before_long_help: zod.string().nullish(), - args: zod.record(cliArg).optional(), - flags: zod.record(cliFlag).optional(), + args: zod.record(cliArg).nullish(), + flags: zod.record(cliFlag).nullish(), }); const flagsAndArgs = zod.record( @@ -83,7 +83,7 @@ const flagsAndArgs = zod.record( zod.string().array(), zod.number(), zod.boolean(), - ]).optional(), + ]).nullish(), ); const cliActionArgs = zod.object({ @@ -94,20 +94,20 @@ const cliActionArgs = zod.object({ const cliCommandActionBase = cliCommandBase.extend({ action: zod.function() .args(cliActionArgs) - .returns(zod.union([zod.promise(zod.void()), zod.void()])).optional(), + .returns(zod.union([zod.promise(zod.void()), zod.void()])).nullish(), }); const cliCommandBindedBase = cliCommandBase.extend({ - action_cb_key: zod.string().optional(), + action_cb_key: zod.string().nullish(), }); const cliCommand: zod.ZodType = cliCommandActionBase.extend({ - sub_commands: zod.lazy(() => zod.array(cliCommand).optional()), + sub_commands: zod.lazy(() => zod.array(cliCommand).nullish()), }); const cliCommandBinded: zod.ZodType = cliCommandBindedBase .extend({ - sub_commands: zod.lazy(() => zod.array(cliCommandBinded).optional()), + sub_commands: zod.lazy(() => zod.array(cliCommandBinded).nullish()), }); type DenoSystemCtor = (gcx: GhjkCtx) => ModuleBase; @@ -117,17 +117,17 @@ export type DenoSystemsRoot = { }; export type CliCommand = zod.input & { - sub_commands?: CliCommand[]; + sub_commands?: CliCommand[] | null; }; export type CliCommandX = zod.infer & { - sub_commands?: CliCommandX[]; + sub_commands?: CliCommandX[] | null; }; export type CliCommandBinded = zod.input & { - sub_commands?: CliCommandBinded[]; + sub_commands?: CliCommandBinded[] | null; }; export type CliCommandBindedX = zod.infer & { - sub_commands?: CliCommandBindedX[]; + sub_commands?: CliCommandBindedX[] | null; }; export type CliFlag = zod.input; diff --git a/src/ghjk/cli.rs b/src/ghjk/cli.rs index 75692e1..a8d062f 100644 --- a/src/ghjk/cli.rs +++ b/src/ghjk/cli.rs @@ -131,8 +131,11 @@ pub async fn cli() -> Res { _ = commands.action(&gcx.config, Some(&systems.config))?; return Ok(ExitCode::SUCCESS); } + Ok(QuickComands::Init { .. }) => { + unreachable!("quick_cli will prevent this") + } Ok(QuickComands::Deno { .. }) => { - unreachable!("deno quick cli will prevent this") + unreachable!("deno_quick_cli will prevent this") } Err(err) => { let kind = err.kind(); @@ -204,6 +207,7 @@ pub async fn try_quick_cli(config: &Config) -> Res> { ))); } } + QuickComands::Init { commands } => commands.action(config).await?, QuickComands::Deno { .. } => unreachable!("deno quick cli will have prevented this"), } @@ -229,11 +233,16 @@ struct Cli { #[derive(clap::Subcommand, Debug)] enum QuickComands { - /// Print different discovored or built values to stdout. + /// Print different discovored or built values to stdout Print { #[command(subcommand)] commands: PrintCommands, }, + /// Setup your working directory for ghjk usage + Init { + #[command(subcommand)] + commands: InitCommands, + }, /// Access the deno cli Deno { #[arg(raw(true))] @@ -243,17 +252,19 @@ enum QuickComands { #[derive(clap::Subcommand, Debug)] enum PrintCommands { - /// Print the path to the data dir used by ghjk. + /// Print the path to the data dir used by ghjk DataDirPath, - /// Print the path to the dir of the currently active ghjk context. + /// Print the path to the dir of the currently active ghjk context GhjkdirPath, - /// Print the path of the ghjkfile used. + /// Print the path of the ghjkfile used GhjkfilePath, - /// Print the extracted and serialized config from the ghjkfile. - Config { - /// Use json format when printing config. + /// Print the currently resolved configuration + Config, + /// Print the extracted and serialized config from the ghjkfile + Serialized { + /* /// Use json format when printing config #[arg(long)] - json: bool, + json: bool, */ }, } @@ -289,18 +300,84 @@ impl PrintCommands { eyre::bail!("no ghjkfile found."); } } - PrintCommands::Config { .. } => match serialized_config { + PrintCommands::Serialized { .. } => match serialized_config { Some(config) => { - let conf_json = serde_json::to_string_pretty(&config)?; - println!("{conf_json}"); + let serialized_json = serde_json::to_string_pretty(&config)?; + println!("{serialized_json}"); true } None => false, }, + PrintCommands::Config {} => { + let conf_json = serde_json::to_string_pretty(&cli_config)?; + println!("{conf_json}"); + true + } }) } } +#[derive(clap::Subcommand, Debug)] +enum InitCommands { + /// Create a starter typescript ghjkfile (ghjk.ts) in the current directory. + Ts { + /// Auto confirm every choice. + #[clap(long)] + yes: bool, + }, + /// Interactively configure working directory for best LSP + /// support of ghjk.ts. + TsLsp { + /// Auto confirm every choice. + #[clap(long)] + yes: bool, + }, +} + +impl InitCommands { + async fn action(self, cli_config: &Config) -> Res<()> { + match self { + InitCommands::Ts { yes } => self.init(cli_config, yes).await, + InitCommands::TsLsp { yes } => self.init_ts_lsp(cli_config, yes).await, + } + } + + async fn init(self, cli_config: &Config, yes: bool) -> Res<()> { + if let Some(path) = &cli_config.ghjkdir { + eyre::bail!( + "conflict, already in ghjkdir context located at {}", + path.display() + ); + } + /* if let Some(path) = cli_config.ghjkfile { + eyre::bail!("conflict, another ghjkfile located at {}", path.display()); + } */ + let cwd = std::env::current_dir().expect_or_log("cwd error"); + let path = cli_config + .ghjkfile + .clone() + .unwrap_or_else(|| cwd.join("ghjk.ts")); + if !crate::utils::file_exists(&path).await? { + const TEMPLATE_TS: &str = include_str!("../../examples/template.ts"); + let re = regex::Regex::new("from \"../(.*)\"; // template-import") + .expect_or_log("regex error"); + + let contents = + re.replace_all(TEMPLATE_TS, format!("from \"{}$1\";", cli_config.repo_root)); + + tokio::fs::write(&path, &contents[..]) + .await + .wrap_err_with(|| format!("error writing out ghjk.ts at {}", path.display()))?; + + info!(path = %path.display(),"written out ghjk.ts"); + } + self.init_ts_lsp(cli_config, yes).await + } + async fn init_ts_lsp(self, _cli_config: &Config, _yes: bool) -> Res<()> { + Ok(()) + } +} + type SysCmdActions = IndexMap; struct SysCmdAction { name: CHeapStr, diff --git a/src/ghjk/config.rs b/src/ghjk/config.rs index b1f6865..b23b9d1 100644 --- a/src/ghjk/config.rs +++ b/src/ghjk/config.rs @@ -1,6 +1,6 @@ use crate::interlude::*; -#[derive(Debug)] +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] pub struct Config { pub ghjkfile: Option, pub ghjkdir: Option, @@ -141,7 +141,7 @@ impl Config { if let Some(path) = &config.ghjkdir { let ignore_path = path.join(".gitignore"); - if !matches!(tokio::fs::try_exists(&ignore_path).await, Ok(true)) { + if !crate::utils::file_exists(&ignore_path).await? { tokio::fs::create_dir_all(path) .await .wrap_err_with(|| format!("error creating ghjkdir at {path:?}"))?; diff --git a/src/ghjk/host.rs b/src/ghjk/host.rs index 4cbcb10..f7d812b 100644 --- a/src/ghjk/host.rs +++ b/src/ghjk/host.rs @@ -112,7 +112,7 @@ pub async fn systems_from_ghjkfile( let (ghjkfile_exists, ghjkfile_hash) = if let Some(path) = &hcx.gcx.config.ghjkfile { ( - matches!(tokio::fs::try_exists(path).await, Ok(true)), + crate::utils::file_exists(path).await?, Some( hashfile::file_digest_hash(hcx.as_ref(), path) .await? diff --git a/src/ghjk/host/hashfile.rs b/src/ghjk/host/hashfile.rs index 5ec14e0..c14985e 100644 --- a/src/ghjk/host/hashfile.rs +++ b/src/ghjk/host/hashfile.rs @@ -5,6 +5,8 @@ use super::HostCtx; #[derive(Debug, Serialize, Deserialize)] pub struct HashObj { pub version: String, + /// The cli config used during serializatin + pub cli_config: crate::config::Config, /// Hashes of all env vars that were read. pub env_var_hashes: indexmap::IndexMap>, /// Hashes of all files that were read. @@ -54,6 +56,7 @@ impl HashObj { .collect(), ) .await?, + cli_config: hcx.gcx.config.clone(), }) } @@ -72,6 +75,12 @@ impl HashObj { #[tracing::instrument(skip(hcx))] pub async fn is_stale(&self, hcx: &HostCtx) -> Res { + { + if self.cli_config != hcx.gcx.config { + trace!("stale cli config"); + return Ok(true); + } + } { let new_digest = env_var_digests( &hcx.config.env_vars, @@ -84,7 +93,7 @@ impl HashObj { } { for path in &self.listed_files { - if !matches!(tokio::fs::try_exists(path).await, Ok(true)) { + if crate::utils::file_exists(path).await? { trace!("stale listed files"); return Ok(true); } diff --git a/src/ghjk/log.rs b/src/ghjk/log.rs index 5aba03c..0d575a6 100644 --- a/src/ghjk/log.rs +++ b/src/ghjk/log.rs @@ -6,7 +6,7 @@ pub fn init() { let eyre_panic_hook = color_eyre::config::HookBuilder::default().display_location_section( std::env::var("RUST_ERR_LOCATION") .map(|var| var != "0") - .unwrap_or(true), + .unwrap_or(cfg!(debug_assertions)), ); #[cfg(not(debug_assertions))] @@ -16,7 +16,7 @@ at https://github.com/metatypedev/ghjk/issues/new. If you can reliably reproduce this panic, try to include the following items in your report: - Reproduction steps -- Output of meta-cli doctor and +- Output of `ghjk print config` and - A panic backtrace. Set the following environment variables as shown to enable full backtraces. - RUST_BACKTRACE=1 - RUST_LIB_BACKTRACE=full diff --git a/src/ghjk/main.rs b/src/ghjk/main.rs index f8324dd..5159240 100644 --- a/src/ghjk/main.rs +++ b/src/ghjk/main.rs @@ -8,7 +8,7 @@ mod interlude { pub use crate::GhjkCtx; - pub use color_eyre::eyre; + pub use color_eyre::{eyre, Section, SectionExt}; pub use denort::deno::{ self, deno_runtime::{ @@ -56,12 +56,26 @@ fn main() -> Res { debug!(version = shadow::PKG_VERSION, "ghjk CLI"); - tokio::runtime::Builder::new_current_thread() + match tokio::runtime::Builder::new_current_thread() .enable_all() .build()? .block_on(cli::cli()) + { + Ok(code) => Ok(code), + Err(err) => { + let err_msg = format!("{err:?}"); + let err_msg = err_msg.split('\n').filter( + |&line| + line != "Backtrace omitted. Run with RUST_BACKTRACE=1 environment variable to display it." + && line != "Run with RUST_BACKTRACE=full to include source snippets." + ).join("\n"); + println!("{err_msg}"); + Ok(std::process::ExitCode::FAILURE) + } + } } +use itertools::Itertools; use shadow_rs::shadow; shadow!(shadow); diff --git a/src/ghjk/systems/deno.rs b/src/ghjk/systems/deno.rs index bee5aa8..64b60a7 100644 --- a/src/ghjk/systems/deno.rs +++ b/src/ghjk/systems/deno.rs @@ -126,6 +126,9 @@ pub async fn systems_from_deno( let mut active_worker = worker.drive_till_exit().await?; let manifests = tokio::select! { + Some(err) = exception_line.recv() => { + return Err(err).wrap_err("error setting up deno systems") + } res = &mut active_worker.exit_code_rx => { let exit_code = res .expect_or_log("channel error") diff --git a/src/ghjk/utils.rs b/src/ghjk/utils.rs index f3d7422..6ecbd09 100644 --- a/src/ghjk/utils.rs +++ b/src/ghjk/utils.rs @@ -239,6 +239,18 @@ pub fn decode_hex_multibase(source: &str) -> eyre::Result> { } } +/// A simpler version of [`tokio::fs::try_exists`] that returns +/// false on a non-existent file and not just on a broken symlink. +#[inline(always)] +pub async fn file_exists(path: &Path) -> Result { + match tokio::fs::try_exists(path).await { + Ok(true) => Ok(true), + Ok(false) => Ok(false), + Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(false), + Err(err) => Err(err), + } +} + pub async fn find_entry_recursive(from: &Path, name: &str) -> Res> { let mut cur = from; loop { diff --git a/tests/envHooks.ts b/tests/envHooks.ts index f62ac73..3b340fb 100644 --- a/tests/envHooks.ts +++ b/tests/envHooks.ts @@ -80,7 +80,7 @@ harness(cases.map((testCase) => ({ ...testCase, fs: { "ghjk.ts": ` -export { sophon } from "$ghjk/hack.ts"; +export { ghjk } from "$ghjk/hack.ts"; import { task, env } from "$ghjk/hack.ts"; env("main") diff --git a/tests/examples.ts b/tests/examples.ts new file mode 100644 index 0000000..3e1def7 --- /dev/null +++ b/tests/examples.ts @@ -0,0 +1,28 @@ +import "../setup_logger.ts"; +import { E2eTestCase, harness } from "./utils.ts"; + +type CustomE2eTestCase = Omit & { + stdin: string; +}; + +// TODO: check each eaxmple works + +const cases: CustomE2eTestCase[] = [{ + name: "template_ts", + stdin: ` +rm ghjk.ts .ghjk -r +ghjk init ts +ghjk sync +`, +}]; + +harness(cases.map((testCase) => ({ + ...testCase, + fs: { + "ghjk.ts": ` +export { ghjk } from "$ghjk/hack.ts"; +`, + }, + ePoints: [{ cmd: "fish", stdin: testCase.stdin }], + name: `examples/${testCase.name}`, +}))); diff --git a/tests/hashfile.ts b/tests/hashfile.ts index a722737..bc79927 100644 --- a/tests/hashfile.ts +++ b/tests/hashfile.ts @@ -49,6 +49,15 @@ __ghjk_get_mtime_ts .ghjk/hash.json > tstamp rm dir/one ghjk sync test (cat tstamp) -lt (__ghjk_get_mtime_ts .ghjk/hash.json); or exit 101 +`, + }, + { + name: "invalidated_cli_config_changed", + stdin: ` +__ghjk_get_mtime_ts .ghjk/hash.json > tstamp +rm dir/one +GHJK_DENO_LOCKFILLE=deno.lock ghjk sync +test (cat tstamp) -lt (__ghjk_get_mtime_ts .ghjk/hash.json); or exit 101 `, }, ]; @@ -57,7 +66,7 @@ harness(cases.map((testCase) => ({ ...testCase, fs: { "ghjk.ts": ` -export { sophon } from "$ghjk/hack.ts"; +export { ghjk } from "$ghjk/hack.ts"; import { task, env } from "$ghjk/hack.ts"; import {stuff} from "./extra.ts" diff --git a/tests/tasks.ts b/tests/tasks.ts index 00b19ea..39ecd4e 100644 --- a/tests/tasks.ts +++ b/tests/tasks.ts @@ -122,7 +122,7 @@ test (cat eddy) = 'ed edd eddy' { name: "anon", ghjkTs: ` -export { sophon } from "$ghjk/hack.ts"; +export { ghjk } from "$ghjk/hack.ts"; import { task } from "$ghjk/hack.ts"; task({ @@ -149,9 +149,8 @@ test (cat eddy) = 'ed edd eddy' ghjkTs: ` import { file } from "$ghjk/hack.ts"; -const ghjk = file({}); +export const ghjk = file({}); -export const sophon = ghjk.sophon; const { env, task } = ghjk; env("main") diff --git a/tests/utils.ts b/tests/utils.ts index bc3e023..6aaf7db 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -81,7 +81,7 @@ exec ${ghjkExePath.resolve().toString()} "$@"`, shellsToHook: [], }); - await $`ghjk print config` + await $`ghjk print serialized` .cwd(tmpDir.toString()) .clearEnv() .env(env); @@ -163,9 +163,7 @@ const confStr = \` ${serializedSecConf} \`; const confObj = JSON.parse(confStr); -const ghjk = file(confObj); - -export const sophon = ghjk.sophon; +export const ghjk = file(confObj); ${tasks} diff --git a/tools/dev.ts b/tools/dev.ts index d6e737c..6284dab 100755 --- a/tools/dev.ts +++ b/tools/dev.ts @@ -49,7 +49,7 @@ await install({ shellsToHook: [], }); -// await $`${ghjkDataDir.join("ghjk").toString()} print config` +// await $`${ghjkDataDir.join("ghjk").toString()} print serialized` // .cwd(devDir.toString()) // .clearEnv() // .env(env); diff --git a/utils/mod.ts b/utils/mod.ts index 464a43d..62d533f 100644 --- a/utils/mod.ts +++ b/utils/mod.ts @@ -607,7 +607,7 @@ export async function detectShellPath(): Promise { } /** - * {@inheritdoc detectShellPath} + * {@inheritDoc detectShellPath} */ export async function detectShell(): Promise { const shellPath = await detectShellPath();