diff --git a/.ghjk/deno.lock b/.ghjk/deno.lock
index 74ec5489..11f98672 100644
--- a/.ghjk/deno.lock
+++ b/.ghjk/deno.lock
@@ -532,6 +532,48 @@
"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/5bb0d24/utils/worker.ts": "ac4caf72a36d2e4af4f4e92f2e0a95f9fc2324b568640f24c7c2ff6dc0c11d62",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/deps/cli.ts": "aac025f9372ad413b9c2663dc7f61affd597820d9448f010a510d541df3b56ea",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/deps/common.ts": "f775710b66a9099b98651cd3831906466e9b83ef98f2e5c080fd59ee801c28d4",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/deps/ports.ts": "3c60d1f7ab626ffdd81b37f4e83a780910936480da8fe24f4ccceaefa207d339",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/files/deno/mod.ts": "1b8204c3df18b908408b2148b48af788e669d0debbeb8ba119418ab1ddf1ab8f",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/files/deno/worker.ts": "8ded400d70a0bd40e281ceb1ffcdc82578443caf9c481b9eee77166472784282",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/host/mod.ts": "af5a9704c3a5b410b322afe0bc8caaaac5b28e1e1591d82b0c5fb53f92cbc97f",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/host/types.ts": "f450d9b9c0eced2650262d02455aa6f794de0edd6b052aade256882148e5697f",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/install/mod.ts": "aa54eb3e119f28d33e61645c89669da292ee00376068ead8f45be2807e7a9989",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/install/utils.ts": "d4634d4fc0e963f540402b4ca7eb5dcba340eaa0d8fceb43af57d722ad267115",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/main.ts": "ecd5e83be2d8f351058ad44424cad1f36dd2e3d76f6e8409afc47682a9eff01a",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/envs/inter.ts": "84805fa208754a08f185dca7a5236de3760bbc1d0df96af86ea5fd7778f827a2",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/envs/mod.ts": "5f37b9f155808f8d6d51e1f16f58c07914d8c7d8070bc5c2fb5076ab748798a7",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/envs/posix.ts": "b22f9564d9773548d537c95265e694a2630c3fe1fd63354d6f4790e275545299",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/envs/reducer.ts": "76ee6974c9d4885da0898e01c498dcfdd99a3652a5a564d679577931a680e781",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/envs/types.ts": "9ff28d47aa60042df42fbb98a46f7689d8111be462237f5fb81771011e429088",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/mod.ts": "fc1cb9176c6557b44ae9c6536fa51c6c4f80ac01fc476d15b0a217e70cb0d176",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/ports/ambient.ts": "823ec8d98702a60e6bfcdbeb64b69dc9f5039e73a1f10e87cd51210c1aaf52d5",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/ports/base.ts": "8ef8a8de372420bddcd63a1b363937f43d898059e99478a58621e8432bcd5891",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/ports/db.ts": "a309d1058f66079a481141c3f1733d928b9af8a37b7ce911b1228f70fd24df0f",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/ports/ghrel.ts": "ebbc30a5c31244131d937eadca73fbc099c9e7bdf0ad4f668766d4388ede143c",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/ports/inter.ts": "b3999e73d73d7f928a8de86e5e2261fe6b1450ceedfb54f24537bf0803532ed0",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/ports/mod.ts": "646cfe12c181f378ffd865890e07ba0a2c92b70cf10687f43de49864ca15c482",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/ports/reducers.ts": "d04e813652101f67f946242df68429ed5540e499fbdb7776b8be5703f16754c8",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/ports/sync.ts": "a7a297f6b098360d56af168692f3cff96f8ceeb5189e5baa249e094f8d9c42ef",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/ports/types.ts": "f4dbd1a3f4b7f539b3a85418617d25adbf710b54144161880d48f6c4ec032eee",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/ports/types/platform.ts": "0ecffeda71919293f9ffdb6c564ddea4f23bc85c4e640b08ea78225d34387fdc",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/ports/utils.ts": "6b14b331cce66bd46e7aec51f02424327d819150f16d3f72a6b0aaf7aee43c09",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/ports/worker.ts": "6b76ba1efb2e47a82582fc48bcc6264fe153a166beffccde1a9a3a185024c337",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/std.ts": "419d6b04680f73f7b252257ab287d68c1571cee4347301c53278e2b53df21c4a",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/tasks/deno.ts": "75b85d8cdc129e56d7bd1bfbfdc4a6f4685e86933c41908e48fbc51be7a57fee",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/tasks/exec.ts": "ddc6bc7cbed464fdd94038a0df8668138411e94e49ae639615b93e734e37d311",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/tasks/inter.ts": "63e8f2860f7e3b4d95b6f61ca56aeb8567e4f265aa9c22cace6c8075edd6210f",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/tasks/mod.ts": "334b18d7c110cc05483be96353e342425c0033b7410c271a8a47d2b18308c73e",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/tasks/types.ts": "072a34bd0749428bad4d612cc86abe463d4d4f74dc56cf0a48a1f41650e2399b",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/modules/types.ts": "c0f212b686a2721d076e9aeb127596c7cbc939758e2cc32fd1d165a8fb320a87",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/port.ts": "c039a010dee7dfd978478cf4c5e2256c643135e10f33c30a09f8db9915e9d89d",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/setup_logger.ts": "f8a206bda0595497d6f4718032d4a959000b32ef3346d4b507777eec6a169458",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/utils/logger.ts": "fcbafb35ae4b812412b9b301ce6d06b8b9798f94ebebe3f92677e25e4b19af3c",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/utils/mod.ts": "25901b5a03625353cc0d9c024daca806eb2513b153faede5ecad73b428542721",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/utils/unarchive.ts": "f6d0e9e75f470eeef5aecd0089169f4350fc30ebfdc05466bb7b30042294d6d3",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/utils/url.ts": "e1ada6fd30fc796b8918c88456ea1b5bbd87a07d0a0538b092b91fd2bb9b7623",
+ "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/utils/worker.ts": "ac4caf72a36d2e4af4f4e92f2e0a95f9fc2324b568640f24c7c2ff6dc0c11d62"
}
}
diff --git a/.ghjk/lock.json b/.ghjk/lock.json
index cad9504a..efabdb07 100644
--- a/.ghjk/lock.json
+++ b/.ghjk/lock.json
@@ -1,80 +1,101 @@
{
"version": "0",
- "platform": "aarch64-darwin",
+ "platform": "x86_64-linux",
"moduleEntries": {
"ports": {
"version": "0",
"configResolutions": {
- "bciqay4m4kmzfduj5t2clgejxgpe5zwper6lyyaxt7rhbjalaqd32nhq": {
- "version": "2.34.1",
- "buildDepConfigs": {},
- "portRef": "git_aa@0.1.0",
- "specifiedVersion": false
- },
"bciqjlw6cxddajjmznoemlmnu7mgbbm7a3hfmnd2x5oivwajmiqui5ey": {
- "version": "v0.2.64",
+ "version": "v0.2.69",
"buildDepConfigs": {},
"portRef": "act_ghrel@0.1.0",
"specifiedVersion": false
},
"bciqao2s3r3r33ruox4qknfrxqrmemuccxn64dze2ylojrzp2bwvt4ji": {
- "version": "3.7.1",
+ "version": "4.0.1",
"buildDepConfigs": {
"cpy_bs_ghrel": {
- "version": "3.12.4",
+ "version": "3.12.7",
"buildDepConfigs": {
"tar_aa": {
- "version": "1.34",
+ "version": "1.35",
"buildDepConfigs": {},
"portRef": "tar_aa@0.1.0",
"specifiedVersion": false
},
"zstd_aa": {
- "version": "v1.4.8,",
+ "version": "v1.5.6,",
"buildDepConfigs": {},
"portRef": "zstd_aa@0.1.0",
"specifiedVersion": false
}
},
"portRef": "cpy_bs_ghrel@0.1.0",
- "specifiedVersion": false
+ "specifiedVersion": true
}
},
"portRef": "pipi_pypi@0.1.0",
"packageName": "pre-commit",
"specifiedVersion": false
},
- "bciqij3g6mmbjn4a6ps4eipcy2fmw2zumgv5a3gbxycthroffihwquoi": {
- "version": "3.12.4",
+ "bciqh4dfyevkzzvmnhuz7lcfqttkg5neg4ewhoxzofyuicavgk6pb7ia": {
+ "version": "3.12.7",
"buildDepConfigs": {
"tar_aa": {
- "version": "1.34",
+ "version": "1.35",
"buildDepConfigs": {},
"portRef": "tar_aa@0.1.0",
"specifiedVersion": false
},
"zstd_aa": {
- "version": "v1.4.8,",
+ "version": "v1.5.6,",
"buildDepConfigs": {},
"portRef": "zstd_aa@0.1.0",
"specifiedVersion": false
}
},
"portRef": "cpy_bs_ghrel@0.1.0",
- "specifiedVersion": false
+ "specifiedVersion": true
},
"bciqj4p5hoqweghbuvz52rupja7sqze34z63dd62nz632c5zxikv6ezy": {
- "version": "1.34",
+ "version": "1.35",
"buildDepConfigs": {},
"portRef": "tar_aa@0.1.0",
"specifiedVersion": false
},
"bciqe6fwheayositrdk7rkr2ngdr4wizldakex23tgivss7w6z7g3q3y": {
- "version": "v1.4.8,",
+ "version": "v1.5.6,",
"buildDepConfigs": {},
"portRef": "zstd_aa@0.1.0",
"specifiedVersion": false
},
+ "bciqoawx3omfmmhaw25mgrujoxl5wkdwfzbmidfqah2zst7cildtcpeq": {
+ "version": "3.8.0.0",
+ "buildDepConfigs": {
+ "cpy_bs_ghrel": {
+ "version": "3.12.7",
+ "buildDepConfigs": {
+ "tar_aa": {
+ "version": "1.35",
+ "buildDepConfigs": {},
+ "portRef": "tar_aa@0.1.0",
+ "specifiedVersion": false
+ },
+ "zstd_aa": {
+ "version": "v1.5.6,",
+ "buildDepConfigs": {},
+ "portRef": "zstd_aa@0.1.0",
+ "specifiedVersion": false
+ }
+ },
+ "portRef": "cpy_bs_ghrel@0.1.0",
+ "specifiedVersion": true
+ }
+ },
+ "portRef": "pipi_pypi@0.1.0",
+ "packageName": "vale",
+ "specifiedVersion": false
+ },
"bciqfvlwwndlfuqibybkgee3fgt7cst5ltpztmm3by6hib5veial5spy": {
"version": "v1.44.2",
"buildDepConfigs": {},
@@ -100,14 +121,14 @@
"installs": [
"bciqe72molvtvcuj3tuh47ziue2oqd6t4qetxn3rsoa764ofup6uwjmi",
"bciqe4zlekl4uqqbhxunac7br24mrf6cdpfrfblahqa4vrgaqjujcl4i",
- "bciqjyl5um6634zwpw6cewv22chzlrsvhedbjahyghhy2zraqqgyiv2q",
+ "bciqpu4klxr3hl6ujhmflrlfd3dxp47ijq26mnathb26ojzwkeggy5ii",
"bciqmgggy7hd5as3zz7pzbx54va7lq657bdxvthntxphhlbsl2434dgq"
],
- "allowedBuildDeps": "bciqjx7llw7t6pfczypzmhbwv7sxaicruj5pdbuac47m4c5qyildiowi"
+ "allowedBuildDeps": "bciqicqqpm2733snzw4pmjnkbw7qbbji7t7cpwj2nbrok6abrzauooqa"
},
"ghjkEnvProvInstSet___test": {
"installs": [],
- "allowedBuildDeps": "bciqjx7llw7t6pfczypzmhbwv7sxaicruj5pdbuac47m4c5qyildiowi"
+ "allowedBuildDeps": "bciqicqqpm2733snzw4pmjnkbw7qbbji7t7cpwj2nbrok6abrzauooqa"
}
}
}
@@ -207,29 +228,39 @@
},
"packageName": "pre-commit"
},
- "bciqjyl5um6634zwpw6cewv22chzlrsvhedbjahyghhy2zraqqgyiv2q": {
+ "bciqpu4klxr3hl6ujhmflrlfd3dxp47ijq26mnathb26ojzwkeggy5ii": {
"port": {
"ty": "denoWorker@v1",
- "name": "cpy_bs_ghrel",
+ "name": "pipi_pypi",
"platforms": [
"x86_64-linux",
"aarch64-linux",
"x86_64-darwin",
"aarch64-darwin",
"x86_64-windows",
- "aarch64-windows"
+ "aarch64-windows",
+ "x86_64-freebsd",
+ "aarch64-freebsd",
+ "x86_64-netbsd",
+ "aarch64-netbsd",
+ "x86_64-aix",
+ "aarch64-aix",
+ "x86_64-solaris",
+ "aarch64-solaris",
+ "x86_64-illumos",
+ "aarch64-illumos",
+ "x86_64-android",
+ "aarch64-android"
],
"version": "0.1.0",
"buildDeps": [
{
- "name": "tar_aa"
- },
- {
- "name": "zstd_aa"
+ "name": "cpy_bs_ghrel"
}
],
- "moduleSpecifier": "file:///ports/cpy_bs.ts"
- }
+ "moduleSpecifier": "file:///ports/pipi.ts"
+ },
+ "packageName": "vale"
},
"bciqmgggy7hd5as3zz7pzbx54va7lq657bdxvthntxphhlbsl2434dgq": {
"version": "1.44.2",
@@ -409,42 +440,6 @@
"portRef": "rustup_rustlang@0.1.0"
}
},
- "bciqjcmf46h2h6teenwbsda35igg4hea6ro5vh6nfieehk4jkuiqaj2a": {
- "manifest": {
- "ty": "denoWorker@v1",
- "name": "rust_rustup",
- "platforms": [
- "x86_64-linux",
- "aarch64-linux",
- "x86_64-darwin",
- "aarch64-darwin",
- "x86_64-windows",
- "aarch64-windows",
- "x86_64-freebsd",
- "aarch64-freebsd",
- "x86_64-netbsd",
- "aarch64-netbsd",
- "x86_64-aix",
- "aarch64-aix",
- "x86_64-solaris",
- "aarch64-solaris",
- "x86_64-illumos",
- "aarch64-illumos",
- "x86_64-android",
- "aarch64-android"
- ],
- "version": "0.1.0",
- "buildDeps": [
- {
- "name": "rustup_rustlang"
- }
- ],
- "moduleSpecifier": "file:///ports/rust.ts"
- },
- "defaultInst": {
- "portRef": "rust_rustup@0.1.0"
- }
- },
"bciqpgt5wsiw4y7qzovqbt2yrdgq5mvhhjpcg6cxzt4w4taudyen44ca": {
"manifest": {
"ty": "denoWorker@v1",
@@ -462,29 +457,38 @@
"portRef": "cargo_binstall_ghrel@0.1.0"
}
},
- "bciqo7cq7igschrhers3wiibbqpaavdf33fdfdalr4cu7gxr7cblifby": {
+ "bciqakxf4wsx3mtku4x5exrl44k4r4kyq6gaw4va5hsb3v26cipmmekq": {
"manifest": {
"ty": "denoWorker@v1",
- "name": "pnpm_ghrel",
+ "name": "cpy_bs_ghrel",
"platforms": [
- "aarch64-linux",
"x86_64-linux",
- "aarch64-darwin",
+ "aarch64-linux",
"x86_64-darwin",
- "aarch64-windows",
- "x86_64-windows"
+ "aarch64-darwin",
+ "x86_64-windows",
+ "aarch64-windows"
],
"version": "0.1.0",
- "moduleSpecifier": "file:///ports/pnpm.ts"
+ "buildDeps": [
+ {
+ "name": "tar_aa"
+ },
+ {
+ "name": "zstd_aa"
+ }
+ ],
+ "moduleSpecifier": "file:///ports/cpy_bs.ts"
},
"defaultInst": {
- "portRef": "pnpm_ghrel@0.1.0"
+ "version": "3.12.7",
+ "portRef": "cpy_bs_ghrel@0.1.0"
}
},
- "bciqoxx4uhfhw77sux6kzqhy6bvxhxkk4cqigrxdrmggillzkfjgjnli": {
+ "bciqboouqnp54fnumgxvl7uay2k6ho4vhlbibvgoyyt5yt3rkwqaohzi": {
"manifest": {
"ty": "denoWorker@v1",
- "name": "asdf_plugin_git",
+ "name": "node_org",
"platforms": [
"aarch64-linux",
"x86_64-linux",
@@ -496,84 +500,93 @@
"version": "0.1.0",
"buildDeps": [
{
- "name": "git_aa"
- }
- ],
- "resolutionDeps": [
- {
- "name": "git_aa"
+ "name": "tar_aa"
}
],
- "moduleSpecifier": "file:///ports/asdf_plugin_git.ts"
+ "moduleSpecifier": "file:///ports/node.ts"
},
"defaultInst": {
- "portRef": "asdf_plugin_git@0.1.0"
+ "portRef": "node_org@0.1.0"
}
},
- "bciqboouqnp54fnumgxvl7uay2k6ho4vhlbibvgoyyt5yt3rkwqaohzi": {
+ "bciqhjmjvlo4aqvwxjkrmoiledobmhkfe7iovqe3wndxiw2aootwn4lq": {
"manifest": {
"ty": "denoWorker@v1",
- "name": "node_org",
+ "name": "rust_rustup",
"platforms": [
- "aarch64-linux",
"x86_64-linux",
- "aarch64-darwin",
+ "aarch64-linux",
"x86_64-darwin",
+ "aarch64-darwin",
+ "x86_64-windows",
"aarch64-windows",
- "x86_64-windows"
+ "x86_64-freebsd",
+ "aarch64-freebsd",
+ "x86_64-netbsd",
+ "aarch64-netbsd",
+ "x86_64-aix",
+ "aarch64-aix",
+ "x86_64-solaris",
+ "aarch64-solaris",
+ "x86_64-illumos",
+ "aarch64-illumos",
+ "x86_64-android",
+ "aarch64-android"
],
"version": "0.1.0",
"buildDeps": [
{
- "name": "tar_aa"
+ "name": "rustup_rustlang"
}
],
- "moduleSpecifier": "file:///ports/node.ts"
+ "moduleSpecifier": "file:///ports/rust.ts"
},
"defaultInst": {
- "portRef": "node_org@0.1.0"
+ "portRef": "rust_rustup@0.1.0",
+ "profile": "minimal"
}
},
- "bciqctvtiscapp6cmlaxuaxnyac664hs3y3xsa5kqh4ctmhbsiehusly": {
+ "bciqoxx4uhfhw77sux6kzqhy6bvxhxkk4cqigrxdrmggillzkfjgjnli": {
"manifest": {
"ty": "denoWorker@v1",
- "name": "cpy_bs_ghrel",
+ "name": "asdf_plugin_git",
"platforms": [
- "x86_64-linux",
"aarch64-linux",
- "x86_64-darwin",
+ "x86_64-linux",
"aarch64-darwin",
- "x86_64-windows",
- "aarch64-windows"
+ "x86_64-darwin",
+ "aarch64-windows",
+ "x86_64-windows"
],
"version": "0.1.0",
"buildDeps": [
{
- "name": "tar_aa"
- },
+ "name": "git_aa"
+ }
+ ],
+ "resolutionDeps": [
{
- "name": "zstd_aa"
+ "name": "git_aa"
}
],
- "moduleSpecifier": "file:///ports/cpy_bs.ts"
+ "moduleSpecifier": "file:///ports/asdf_plugin_git.ts"
},
"defaultInst": {
- "portRef": "cpy_bs_ghrel@0.1.0"
+ "portRef": "asdf_plugin_git@0.1.0"
}
},
- "bciqjx7llw7t6pfczypzmhbwv7sxaicruj5pdbuac47m4c5qyildiowi": {
+ "bciqicqqpm2733snzw4pmjnkbw7qbbji7t7cpwj2nbrok6abrzauooqa": {
"tar_aa": "bciqb6ua63xodzwxngnbjq35hfikiwzb3dclbqkc7e6xgjdt5jin4pia",
"git_aa": "bciqfl5s36w335ducrb6f6gwb3vuwup7vzqwwg67pq42xtkngsnxqobi",
"curl_aa": "bciqcfe7qyxmokpn6pgtaj35r5qg74jkehuu6cvyrtcsnegvwlm64oqy",
"unzip_aa": "bciqgkpwxjmo5phw5se4ugyiz4xua3xrd54quzmk7wdwpq3vghglogjy",
"zstd_aa": "bciqmcvyepuficjj3mwshsbfecwdmzch5gwxqo557icnq4zujtdllh4a",
"rustup_rustlang": "bciqk4ivbyqvpxwcaj5reufmveqldiizo6xmqiqq7njtaczgappydoka",
- "rust_rustup": "bciqjcmf46h2h6teenwbsda35igg4hea6ro5vh6nfieehk4jkuiqaj2a",
"cargo_binstall_ghrel": "bciqpgt5wsiw4y7qzovqbt2yrdgq5mvhhjpcg6cxzt4w4taudyen44ca",
- "pnpm_ghrel": "bciqo7cq7igschrhers3wiibbqpaavdf33fdfdalr4cu7gxr7cblifby",
- "asdf_plugin_git": "bciqoxx4uhfhw77sux6kzqhy6bvxhxkk4cqigrxdrmggillzkfjgjnli",
+ "cpy_bs_ghrel": "bciqakxf4wsx3mtku4x5exrl44k4r4kyq6gaw4va5hsb3v26cipmmekq",
"node_org": "bciqboouqnp54fnumgxvl7uay2k6ho4vhlbibvgoyyt5yt3rkwqaohzi",
- "cpy_bs_ghrel": "bciqctvtiscapp6cmlaxuaxnyac664hs3y3xsa5kqh4ctmhbsiehusly"
+ "rust_rustup": "bciqhjmjvlo4aqvwxjkrmoiledobmhkfe7iovqe3wndxiw2aootwn4lq",
+ "asdf_plugin_git": "bciqoxx4uhfhw77sux6kzqhy6bvxhxkk4cqigrxdrmggillzkfjgjnli"
}
}
}
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 0fae416b..cd2b6816 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,6 +1,7 @@
{
"deno.enablePaths": [
- "."
+ ".",
+ "ghjk.ts"
],
"deno.suggest.completeFunctionCalls": true,
"deno.inlayHints.variableTypes.enabled": true,
@@ -18,7 +19,13 @@
"editor.defaultFormatter": "denoland.vscode-deno"
},
"cSpell.words": [
- "ghjk"
+ "DENO",
+ "ghjk",
+ "ghjkfile",
+ "Hashfile",
+ "POSIX",
+ "runtimes",
+ "sophon"
],
"spellright.language": [
"en-US-10-1."
diff --git a/README.md b/README.md
index 70c34cde..d64ac403 100644
--- a/README.md
+++ b/README.md
@@ -11,9 +11,9 @@ ghjk /gk/ is a programmable runtime manager and an attempt at a successor for [a
## Introduction
-ghjk offers a unified abstraction to manage package managers (e.g. cargo, pnpm, poetry), languages runtimes (e.g. nightly rust, node@18, python@latest) and developer tools (e.g. pre-commit, eslint, protoc). It enables you to define a consistent environment across your dev environments, CI/CD pipelines and containers keeping everything well-defined in your repo and providing a great DX.
-
-ghjk was designed to be an intermediate alternative between [Earthly](https://github.com/earthly/earthly)/[Dagger](https://github.com/dagger/dagger) (lighter and more flexible) and complex building tools like [Bazel](https://github.com/bazelbuild/bazel/)/[Nix-based devenv](https://github.com/cachix/devenv) (simpler and more extensible). This makes it especially convenient for mono-repos and long-lived projects. See [Metatype](https://github.com/metatypedev/metatype) and its [ghjkfile](https://github.com/metatypedev/metatype/blob/main/ghjk.ts) for a real world example.
+ghjk offers a unified abstraction to manage package managers (e.g. cargo, pnpm, poetry), languages runtimes (e.g. nightly rust, node@18, python@latest) and developer tools (e.g. pre-commit, eslint, protoc).
+It enables you to define a consistent environment across your dev environments, CI/CD pipelines and containers keeping everything well-defined in your repo and providing a great DX.
+This makes it especially convenient for mono-repos and long-lived projects. See [Metatype](https://github.com/metatypedev/metatype) and its [ghjkfile](https://github.com/metatypedev/metatype/blob/main/ghjk.ts) for a real world example.
@@ -21,58 +21,56 @@ ghjk was designed to be an intermediate alternative between [Earthly](https://gi
## Features
-- Soft-reproducable developer environments.
-- Install posix programs from different backend like npm, pypi, crates.io.
-- Tasks written in typescript.
-- Run tasks when entering/exiting envs.
+- Install standalone posix programs or those found on different backends and registries
+ - [npm](./ports/npmi.ts)
+ - [pypi](./ports/pipi.ts)
+ - [crates.io](./ports/cargobi.ts)
+ - [ ] [Github releases](https://github.com/metatypedev/ghjk/issues/79)
+- Tasks written in typescript
+ - Ergonomically powered by [`dax`](https://github.com/dsherret/dax).
+ - Built on Deno, most dependencies are [an import away](https://docs.deno.com/runtime/fundamentals/modules/#importing-third-party-modules-and-libraries).
+- Soft-reproducible posix environments.
+ - Declaratively compose envs for developer shells, CI and tasks.
+ - Run tasks when entering/exiting envs.
## Getting started
-```bash
-# stable
-curl -fsSL https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/install.sh | bash
-# latest (main)
-curl -fsSL https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/install.sh | GHJK_VERSION=main bash/fish/zsh
-```
+Before anything, make sure the following programs are available on the system.
-In your project, create a configuration file called `ghjk.ts` that look something like:
+- git
+- tar (preferably GNU tar)
+- curl
+- unzip
+- zstd
-```ts
-// NOTE: All the calls in your `ghjk.ts` file are ultimately modifying the 'sophon' proxy
-// object exported here.
-// WARN: always import `hack.ts` file first
-export { sophon } from "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/hack.ts";
-import {
- install,
- task,
-} from "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/hack.ts";
-import node from "https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/ports/node.ts";
-
-// install programs (ports) into your env
-install(node({ version: "14.17.0" }));
-
-// write simple scripts and execute them using
-// `$ ghjk x greet`
-task("greet", async ($, { argv: [name] }) => {
- await $`echo Hello ${name}!`;
-});
+Install the ghjk cli using the installer scripts like so:
+
+```bash
+curl -fsSL https://raw.github.com/metatypedev/ghjk/v0.2.1/install.sh | bash
```
-Use the following command to then access your environment:
+Use the following command to create a starter `ghjk.ts` in your project directory:
```bash
-ghjk sync
+ghjk init ts
```
### Environments
Ghjk is primarily configured through constructs called "environments" or "envs" for short.
-They serve as recipes for making (mostly) reproducable posix shells.
+They serve as recipes for making (mostly) reproducible posix shells.
```ts
-export { sophon } from "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/hack.ts";
-import * as ghjk from "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/hack.ts";
-import * as ports from "https://raw.githubusercontent.com/metatypedev/ghjk/v0.2.1/ports/mod.ts";
+import { file } from "https://raw.github.com/metatypedev/ghjk/v0.2.1/mod.ts";
+// ports are small programs that install sowtware to your envs
+import * as ports from "https://raw.github.com/metatypedev/ghjk/v0.2.1/ports/mod.ts";
+
+const ghjk = file({});
+
+// NOTE: `ghjk.ts` files are expected to export this sophon object
+// all the functions on the ghjk object are ultimately modifying the 'sophon' proxy
+// object exported here.
+export const sophon = ghjk.sophon;
// top level `install`s go to the `main` env
ghjk.install(ports.protoc());
@@ -105,8 +103,10 @@ ghjk.env({
installs: [ports.cargobi({ crateName: "cargo-chef" }), ports.zstd()],
});
-// builder syntax is also availaible
-ghjk.env("ci").var("CI", "1").install(ports.opentofu_ghrel());
+// builder syntax is also available
+ghjk.env("ci")
+ .var("CI", "1")
+ .install(ports.opentofu_ghrel());
// each task describes it's own env as well
ghjk.task({
@@ -114,93 +114,44 @@ ghjk.task({
inherit: "dev",
fn: () => console.log("online"),
});
-```
-
-Once you've configured your environments:
-
-- `$ ghjk envs cook $name` to reify and install an environment.
-- `$ ghjk envs activate $name` to switch to an environment.
-- And **most** usefully, `$ ghjk sync $name` to cook and _then_ activate an
- environment.
- - If shell is already in the specified env, it only does cooking.
- - Make sure to `sync` or `cook` your envs after changes.
-- If no `$name` is provided, most of these commands will operate on the default
- or currently active environment.
-
-### Ports
-
-TBD: this feature is in development.
-Look in the [kitchen sink](./examples/kitchen/ghjk.ts) for what's currently implemented.
-
-### Tasks
-
-TBD: this feature is still in development.
-Look in the [tasks example](./examples/tasks/ghjk.ts) for what's currently implemented.
-#### Anonymous tasks
-
-Tasks that aren't give names cannot be invoked from the CLI.
-They can be useful for tasks that are meant to be common dependencies of other tasks.
-
-### `hack.ts`
-
-The imports from the `hack.ts` module, while nice and striaght forward to use, hold and modify global state.
-Any malicious third-party module your ghjkfile imports will thus be able to access them as well, provided they import the same version of the module.
-
-```ts
-// evil.ts
-import { env, task } from "https://.../ghjk/hack.ts";
-
-env("trueBase").install(ports.act(), ports.pipi({ packageName: "ruff" }));
-
-env("test").vars({ DEBUG: 1 });
-
-// `stdSecureConfig` is a quick way to make an up to spec `secureConfig`.
-export const secureConfig = stdSecureConfig({
- defaultBaseEnv: "trueBase",
- defaultEnv: "test",
+ghjk.config({
+ defaultBaseEnv: "main",
+ defaultEnv: "main",
// by default, nodejs, python and other runtime
// ports are not allowed to be used
// during the build process of other ports.
// Disable this security measure here.
- // (More security features inbound!.)
enableRuntimes: true,
});
```
-To prevent this scenario, the exports from `hack.ts` inspect the call stack and panic if they detect more than one module using them.
-This means if you want to spread your ghjkfile across multiple modules, you'll need to use functions described below.
-
-> [!CAUTION]
-> The panic protections of `hack.ts` described above only work if the module is the first import in your ghjkfile.
-> If a malicious script gets imported first, it might be able to modify global primordials and get around them.
-> We have more ideas to explore on hardening Ghjk security.
-> This _hack_ is only a temporary compromise while Ghjk is in alpha state.
-
-The `hack.ts` file is only optional though and a more verbose but safe way exists through...
+Once you've configured your environments:
-```ts
-import { file } from "https://.../ghjk/mod.ts";
+- `$ ghjk envs cook $name` to reify and install an environment.
+- `$ ghjk envs activate $name` to activate/switch to an environment.
+- And **most** usefully, `$ ghjk sync $name` to cook and _then_ activate an
+ environment.
+ - Make sure to `sync` or `cook` your envs after changes.
+- If no `$name` is provided, most of these commands will operate on the default
+ or currently active environment.
-const ghjk = file({
- // items from `config()` are availaible here
- defaultEnv: "dev",
+More details can be found in the [user manual](./docs/manual.md).
- // can even directly add installs, tasks and envs here
- installs: [],
-});
+## Development
-// we still need this export for this file to be a valid ghjkfile
-export const sophon = ghjk.sophon;
+Use the following command to enter a shell where the ghjk CLI is based on the code that's in the working tree.
+This will setup a separate installation at `.dev`.
-// the builder functions are also accessible here
-const { install, env, task, config } = ghjk;
+```bash
+$ deno task dev bash/fish/zsh
```
-If you intend on using un-trusted third-party scripts in your ghjk, it's recommended you avoid `hack.ts`.
-
-## Development
+Run the tests in the repository through the deno task:
```bash
-$ cat install.sh | GHJK_INSTALLER_URL=$(pwd)/install.ts bash/fish/zsh
+$ deno task test
```
+
+Most tests are isolated from each other using containers.
+Set `$GHJK_TEST_E2E_TYPE` to `local` to use the local test runner.
diff --git a/docs/available-commands.md b/docs/available-commands.md
deleted file mode 100644
index 79353a4d..00000000
--- a/docs/available-commands.md
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-| Command | Description | Subcommands/Flags |
-|----------------|-------------|-------------------|
-| ```ghjk sync``` | Synchronize your shell to what's in your config. | |
-| ```ghjk envs ls``` | List environments defined in the ghjkfile. | |
-| ```ghjk envs activate ``` | Activate an environment. | |
-| ```ghjk ports resolve``` | Resolve all installs declared in config. | |
-| ```ghjk ports outdated``` | Show a version table for installs. | `--update-all`: update all installs which their versions is not specified in the config.
`--update-only `: update a selected install |
-| ```ghjk print``` | Emit different discovered and built values to stdout. | |
-| ```ghjk deno``` | Access the deno cli. | |
-| ```ghjk completions``` | Generate shell completions. | |
-
-You can use the following flag to get help around the CLI.
-`ghjk --help` or `ghjk -h`
diff --git a/docs/installation-vars.md b/docs/installation-vars.md
new file mode 100644
index 00000000..967a944a
--- /dev/null
+++ b/docs/installation-vars.md
@@ -0,0 +1,15 @@
+# Installer vars
+
+| Env vars | Desc | Default |
+| -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ |
+| `GHJK_VERSION` | Git tag/ref of the ghjk repo to install from. | Latest release tag. |
+| `GHJK_SHARE_DIR` | Root directory for ghjk installation. | `$HOME/.local/share/ghjk` |
+| `GHJK_INSTALLER_URL` | Uri to the typescript section of installer script. | `install.ts` file from the ghjk repo under |
+| `GHJK_INSTALL_EXE_DIR` | Location to install the `ghjk` exec. | `$HOME/.local/bin` |
+| `GHJK_INSTALL_SKIP_EXE` | Weather or not to skip install the `ghjk` CLI to `GHJK_INSTALL_EXE_DIR`. | `false` |
+| `GHJK_INSTALL_DENO_EXEC` | Alternative deno exec to use. If provided, no separate Deno CLI is downloaded. It's generally preferable for ghjk to manage it's own Deno versions still. | A Deno CLI is installed to `$GHJK_SHARE_DIR/bin` |
+| `DENO_VERSION` | Deno version to install if `GHJK_INSTALL_DENO_EXEC` is not test. | Deno version used for ghjk development. |
+| `GHJK_INSTALL_HOOK_SHELLS` | Comma separated list of shells to hook. | `bash,fish,zsh` |
+| `GHJK_INSTALL_HOOK_MARKER` | Marker to use when installing shell hooks. | `ghjk-hook-marker` |
+| | | |
+| `GHJK_INSTALL_NO_LOCKFILE` | Disable use of a Deno lockfile for the ghjk program. | |
diff --git a/docs/known-issues.md b/docs/known-issues.md
new file mode 100644
index 00000000..3a43f1e3
--- /dev/null
+++ b/docs/known-issues.md
@@ -0,0 +1,33 @@
+# Known issues
+
+## Cache invalidation of imported scripts
+
+Currently, ghjk is unable to track changes to local typescript files imported by the ghjk.ts file.
+You can fore re-serialization of the ghjkfile by deleting the `.ghjk/hash.json` file.
+
+## Github API rate-limit
+
+The Github API is rate-limited to 60 calls per hour for un-authenticated requests.
+Since many of the ports get their files from github releases, its easy to get past this limit especially in CI contexts.
+This will manifest in failed 403 responses from ports trying to access the Github API.
+
+The best solution to this problem is to provide Github authentication tokens using the `GITHUB_TOKEN` environment variable.
+Authenticated requests have a rate-limit of 5000 calls per hour.
+Most of the ports will make use of this in their API calls if this environment variable is detected.
+
+If you're using Github CI runners, this environment variable is [automatically](https://docs.github.com/en/actions/security-for-github-actions/security-guides/automatic-token-authentication) provided for you.
+Otherwise, you'll need to generate [personal access tokens](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens) which can be used for this purpose.
+More information on the Github rate limits can be found [here](https://docs.github.com/en/rest/using-the-rest-api/rate-limits-for-the-rest-api?apiVersion=2022-11-28).
+
+## Leaking secure Github tokens
+
+Currently, any values captured by ports have to be persisted in the lockfile.
+As most ports today make use of the `GITHUB_TOKEN` environment variable, it's easy to leak these tokens into the ghjk lockfile which is intended to be committed.
+Until a better solution can be devised for this, it's recommended to avoid using `GITHUB_TOKEN`s on the development machine where commits are authored.
+If the token ends up in your lockfile, be sure to clean it out before a commit is made.
+
+```bash
+rm .ghjk/lock.json
+# this command will re-resolve all ports
+ghjk p resolve
+```
diff --git a/docs/manual.md b/docs/manual.md
new file mode 100644
index 00000000..b0282fba
--- /dev/null
+++ b/docs/manual.md
@@ -0,0 +1,481 @@
+# User Manual
+
+Ghjk is a toolkit for declarative and programmatic configuration of POSIX runtime environments.
+Currently in heavy development, it features working implementations of:
+- Tool installation and management
+- Task runner
+- Declarative and dynamic environment variables
+
+This user manual is designed to be read on the Github web app within the repo that hosts the ghjk codebase.
+
+
+## Installation
+
+Before anything, the ghjk CLI should be installed.
+There are installer scripts available in the repo.
+
+
+```bash
+# stable
+curl -fsSL https://raw.github.com/metatypedev/ghjk/v0.2.1/install.sh | bash
+```
+
+This will install the CLI and add configuration your shell rc files the necessary hooks ghjk needs to function.
+Installation can be customized through a number of environment variables that can be found [here](./installation-vars.md).
+
+## `ghjk.ts`
+
+Ghjk is configured through a ghjkfile.
+Currently, a typescript based ghjkfile is available and the rest of this documents will use typescript for configuration.
+Use the following command to create a starter file in the current directory:
+
+```bash
+# initialize a `ghjk.ts` file
+ghjk init ts
+```
+
+Look through the following snippet to understand the basic structure of a `ghjk.ts` file.
+
+```ts
+// import the file function from `mod.ts` using the version of ghjk
+// one's using. For example
+// https://raw.github.com/metatypedev/ghjk/v0.2.1/
+import { file } from ".../mod.ts";
+// import the port for the node program
+import node from ".../ports/node.ts";
+
+const ghjk = file();
+
+// all ghjk.ts files are expected to export this special `sophon` object
+// all the functions from the ghjk object are modifying the sophon
+export const sophon = ghjk.sophon;
+
+// install programs (ports) into your env
+ghjk.install(
+ node({ version: "14.17.0" }),
+);
+
+// declare tasks to be available from the command line.
+ghjk.task("greet", async ($) => {
+ await $`echo Hello ${$.argv}!`;
+});
+```
+
+One can look at the [examples](../examples/) found in the ghjk repo for an exploration of the different features available.
+
+## `$GHJK_DIR`
+
+Once you have a ghjkfile ready to go, the ghjk CLI can be used to access all the features your ghjkfile is using.
+Augmenting the CLI are the hooks that were installed into your shells rc file (startup scripts like `~/.bashrc`).
+These hooks check and modify your shell environment when you create a new one or `cd` (change directory) into a ghjk relevant directory.
+
+What constitutes a ghjk relevant directory?
+- One that contains a recognized ghjkfile format like any file called `ghjk.ts`
+- One that contains a `.ghjk` directory
+
+Note that if any parent directory contains these files, the current directory is considered part of that ghjk context.
+The `$GHJKFILE` environment variable can be set to point the CLI and hooks at a different ghjkfile.
+
+The `.ghjk` dir is used by ghjk for different needs and contains some files you'll want to check into version control.
+It includes its own `.gitignore` file by default that excludes all items not of interest for version control.
+The `$GHJK_DIR` variable can be used to point the CLI at a different directory.
+
+## Serialized
+
+The ghjk CLI loads your typescript file in a worker to get at the actual configuration.
+This process is called _serialization_.
+The CLI generally operates on the output of this serialization though it might need to load your ghjkfile in a worker again, to execute task functions you've written for example.
+While the details of the output are not important, this _serialize then do_ workflow defines how ghjk functions as we should see.
+
+The ghjk CLI serializes any discovered ghjkfile immediately when invoked.
+In fact, what commands are available on the CLI are determined by the outputs of serialization.
+If you declared tasks for example, ghjk will add the `tasks` sections to invoke them.
+
+To look at what the ghjkfile looks like serialized, you can use the following command:
+
+```bash
+# look at the serialized form the ghjkfile
+ghjk print config
+```
+
+#### The Hashfile
+
+Loading up typescript files in workers is not the quickest of operations as it turns out.
+Ghjk caches output of this serialization to improve the latency of the CLI commands.
+This raises the question how well the cache invalidation works in ghjk and that's a good question.
+Cache invalidation is one of the hardest problems in computer science according to lore.
+
+Thankfully, through the great sandbox provided through Deno's implementation, the cache is invalidated when the following items change:
+- The contents of the ghjkfile
+- Files accessed during serialization
+- Environment variables read during serialization
+
+This doesn't cover everything though and the `ghjk.ts` implementation generally assumes a declarative paradigm of programming.
+You'll generally want to avoid any logic that's deterministic on inputs like time or RNGs.
+
+There are still a couple of glaring omissions from this list that will be addressed as ghjk matures.
+If you encounter any edge cases or want to force re-serialization, you can remove the hashfile at `.ghjk/hash.json` which contains hashes for change tracking.
+
+```bash
+# remove the hashfile to force re-serialization
+$ rm .ghjk/hash.json
+$ ghjk --help
+```
+
+
+
+
+#### The Lockfile
+
+The cached value of the serialization results are stored in the lockfile.
+The lockfile is what the different modules of ghjk use to store transient information that needs to be tracked across serializations.
+Currently, this is mainly used by the port modules to retain version numbers resolved during installation which is important for the basic need of reproducibility.
+
+To maintain reproducibility across different machines, this file needs to be checked into version control.
+Unfortunately, this can lead to version conflicts during git merges for example.
+
+One can always remove the `.ghjk/lock.json` to remove the lockfile and recreate it.
+But this can not only lead to loss of information, it can take a long time since the ports module must query different package registries to resolve versions and more.
+
+The best way to resolve ghjk merge conflicts is to:
+- Resolve the ghjkfile conflict in a traditional manner
+- Instead of manually resolving the lockfile, just pick one version entirely
+ - In git, easier to remove any changes in the merge and revert to the base/HEAD branch
+- Re-serialize by invoking the ghjk CLI
+
+This simple steps make sure that the _lockfile_ reflect what's in the latest _ghjkfile_ without needing to re-resolve the world.
+Of course, if the discarded version of the lockfile contained new versions, they'll be re-resolved possibly to a different version.
+But generally, if the versions specified in ghjkfile are tight enough, it'll resolve the same values as before.
+If versions are important, it's good to explicitly specify them in your ghjkfile.
+
+The lockfile format itself is still in flux and there are plans to improve the merge conflict experience going forward.
+
+## Tasks
+
+Tasks are pretty simple to use.
+You declare them in your ghjkfile, using typescript functions, and then invoke them from the the CLI.
+The CLI will then load your ghjkfile in a worker and execute your function.
+
+```ts
+import { file } from ".../mod.ts";
+
+const ghjk = file();
+
+ghjk.task("greet", async ($) => {
+ await $`echo Hello ${$.argv}!`;
+});
+```
+
+```bash
+# list the available tasks
+$ ghjk tasks
+
+# x is an alias for tasks
+$ ghjk x
+
+# invoke the greet task
+# ghjk x greet ghjk
+```
+
+The `$` object is a enhanced version of the one from the [dax](https://jsr.io/david/jsr) library.
+Amongst many things, it allows easy execution of shell commands in a cross platform way.
+Look at the official documentation for all of it's illustrious powers.
+
+Tasks can also depend on each other meaning that the depended on task is always executed first.
+Any arguments to the tasks are also passed on the `$` object or the second parameter object.
+Look at the [tasks example](../examples/tasks/ghjk.ts) for more details..
+
+## Envs
+
+Ghjk's environments, simply put, are a set of configurations for a POSIX environment.
+POSIX environments are primarily defined by the current working directory and the set environment variables.
+Ghjk envs then allow you:
+- Set environment variables of course
+- Add existing paths or newly installed program (ports) to the special `$PATH` variables
+- Execute logic on entering and exiting envs
+- Do all of this declaratively and in a composable manner
+
+Let's look at how one configures an environment using the `ghjk.ts` file:
+
+```ts
+import { file } from ".../mod.ts";
+
+const ghjk = file();
+
+ghjk.env("my-env")
+ .var("MY_VAR", "hello POSIX!")
+ // we can return strings from typescript functions for dynamic
+ // variables
+ .var("MY_VAR_DYN", () => `Entered at ${new Date().toJSON()}`)
+ .onEnter(task(($) => console.log(`entering my-env`)))
+ .onExit(task(($) => console.log(`entering my-env`)))
+ ;
+```
+
+By default, your ghjkfile has an env called `main`.
+Envs can inherit from each other and by default inherit from the `main` environment.
+Inheritance is additive based for most env properties and allows easy composition.
+Please look at the [envs example](../examples/envs/ghjk.ts) or the [kitchen sink](../examples/kitchen/ghjk.ts) example which show all the knobs available on envs.
+
+You can then access the envs feature under the `envs` section of the CLI:
+
+```bash
+# look at avail sub commands
+$ ghjk envs
+# alias for envs
+$ ghjk e
+# list available envs
+$ ghjk envs ls
+```
+
+Before we can _activate_ an environment, it needs to be _cooked_.
+That is, entering an environment is a two step process.
+
+Cooking is what we call preparing the environment.
+Required programs for the env are resolved and installed.
+The shims for these programs are prepared.
+The shell scripts to activate/deactivate it are prepared.
+The results of env cooking are stored inside the `.ghjk/envs` directory.
+
+```bash
+# cook a named env
+$ ghjk e cook my-env
+```
+
+Once an environment is _cooked_, _activation_ is simple enough.
+The name of the currently active environment is set to the `$GHJK_ENV` environment variable.
+
+```bash
+# activate using the CLI
+$ ghjk e activate my-env
+$ echo $GHJK_ENV
+# my-env
+$ echo $MY_VAR
+# hello POSIX!
+```
+
+When an env is activated in a shell session, the `ghjk_deactivate` command will be made available for deactivation.
+This will remove the set variables and restore old ones if any were overwritten.
+The ghjk shell hooks auto-deactivate any active environments from you shell, when it `cd`s away into a directory that's not part of the context.
+
+```bash
+$ ghjk_deactivate
+$ echo $MY_VAR
+#
+```
+
+Note that the CLI activate command depends on the the ghjk shell hooks being available.
+If not in an interactive shell, look at the CI section of this document for what options are available.
+
+#### `sync`
+
+The _cook_ and _activate_ process is common enough that there's a command available that does both, `sync`.
+The `sync` command and both the `cook` and `activate` commands will operate on the currently active env if no env name argument is provided.
+If no value is found at `$GHJK_ENV`, they'll use the set default env as described in the next section.
+
+```bash
+# cook and activate an environment
+$ ghjk sync my-env
+```
+
+### Default Env
+
+By default, the `main` environment is the one that's activated whenever you `cd` into the ghjk context.
+You can change which env is activated by default using the `defaultEnv` setting.
+
+```bash
+ghjk.config({
+ defaultEnv: "my-env",
+});
+```
+
+`main` also serves as the default base all other envs inherit from.
+The `defaultBaseEnv` parameter can be used to change this.
+
+```bash
+ghjk.config({
+ defaultBaseEnv: "main",
+});
+```
+
+## Ports
+
+Ports are small programs that ghjk executes to download and install programs.
+When the env that includes a port installation is activated, a path to shims of the programs will be added to the special `$PATH` env variables.
+This extends to modifying the appropriate `$PATH` variables for libraries or any environment variables needed for the program to function.
+Currently, ports that are written in Deno flavoured typescript are supported and there's a small collection of such programs provided in the ghjk repository.
+
+The modules that implement port programs are also expected to expose a `conf` function as their default export.
+The `conf` functions prove as a point of configuration for the port installation.
+They return `InstallConfig` objects that describe user configuration along with where the port can be found and how to use it.
+Any `InstallConfig` objects included in an env will then be resolved and installed when it's cooked.
+
+```ts
+// the default export corresponds to the `conf` function
+import node from ".../ports/node.ts";
+// the npmi installs executable packages from npm
+import npmi from ".../ports/node.ts";
+
+// top level `install` calls go to the `main` env
+ghjk.install(
+ // configure installation for the node port
+ node({ version: "1.2.3" }),
+ // configure npmi to install the eslint package
+ npmi({ packageName: "eslint", version: "9" })
+);
+```
+
+We can then `sync` the main env to install and access the programs.
+
+```bash
+# cook and activate
+$ ghjk sync main
+# the programs provided by the ports should now be available
+$ node --version
+$ eslint --version
+```
+
+### `buildDeps`
+
+While the Deno standard library and ESM url imports allow ports to do a lot, some ports require other programs to succeed at their tasks.
+For example, the `npmi` port, which installs executable packages from npm, relies on the `npm` program for the actual functionality.
+This is achieved by allowing ports to depend on other ports that they can use for tasks such as resolving available versions, downloading appropriate files, archive extraction, compilation...etc.
+
+As a soft security measure, ports are restricted to what other port they're allowed to depend on.
+The default set includes common utilities like `curl`, `git`, `tar` and others which are used by most ports.
+More ports can be easily added to the allowed port dep set.
+
+```ts
+import { file } from ".../mod.ts";
+// barrel export for ports in the ghjk repo
+import * as ports from "../../ports/mod.ts";
+
+const ghjk = file();
+
+ghjk.install(
+ ports.npmi({ packageName: "tsx" })
+)
+
+ghjk.config({
+ allowedBuildDeps: [
+ ports.node(),
+ ],
+});
+```
+
+The standard set of allowed port deps can be found [here](../modules/ports/std.ts).
+
+#### `enableRuntimes`
+
+The default set excludes scripting runtimes like `python` and `node` as another soft security measure.
+Commonly used ports like `npmi`, `pipi` and `cargobi` rely on such ports to build and install programs from popular registries.
+The `enableRuntimes` toggle can be used to add these common dependencies to the allowed build set.
+
+```ts
+ghjk.config({
+ enableRuntimes: true,
+});
+```
+
+One can look at the list of ports included by the flag [here](../modules/ports/std_runtime.ts)
+
+#### Ambient ports
+
+Ambient ports reuse programs already available on the system instead of downloading and installing one from the internet.
+For a variety of reasons, the standard set of allowed port deps includes a number of these.
+Please install the following programs first before attempting to use ghjk ports:
+
+- git
+- tar (preferably GNU tar)
+- curl
+- unzip
+- zstd
+
+### Writing ports
+
+The ports implementations is going through a lot of breaking changes.
+If you need to author a new port right away, please look at the available implementations.
+
+## CI
+
+While the ghjk CLI and hooks are primarily designed for interactive shells in mind, they also support non-interactive use cases like scripts for CI jobs and for use in build tools.
+The primarily difference between the two scenarios is how activation of envs is achieved as we shall see below.
+
+### Installation
+
+The standard installation script is the best way to install ghjk in CI environments.
+The environment [variables](./installation-vars.md) used for the installer customization come in extra handy here.
+Namely, it's good practice to:
+- Make sure the `$GHJK_VERSION` is the one used by the ghjkfile.
+- Specify `$GHJK_SHARE_DIR` to a location that can be cached by your CI tooling. This is where ports get installed.
+- Specify `$GHJK_INSTALL_EXE_DIR` to a location that you know will be in `$PATH`. This is where the ghjk CLI gets installed to.
+
+```dockerfile
+# sample of how one would install ghjk for use in a Dockerfile
+ARG GHJK_VERSION=v0.2.1
+# /usr/bin is available in $PATH by default making ghjk immediately avail
+RUN GHJK_INSTALL_EXE_DIR=/usr/bin \
+ curl -fsSL https://raw.github.com/metatypedev/ghjk/$GHJK_VERSION/install.sh | bash
+```
+
+### Activation
+
+When working on non-interactive shells, the ghjk shell hooks are not available.
+This means that the default environment won't be activated for that CWD nor will any changes occur on changing directories.
+It also prevents the `ghjk envs activate` command from functioning which requires that these hooks be run before each command.
+In such scenarios, one can directly `source` the activation script for the target env from the `.ghjk` directory.
+
+```bash
+# cooking must be done to make the activations scripts available
+ghjk cook my-env
+# there are scripts for POSIX and fish shells
+source .ghjk/envs/my-env/activate.sh
+echo $GHJK_ENV
+# my-env
+echo $MY_VAR
+# hello POSIX!
+```
+
+Make sure to activate the environment for every shell session in your CI scripts.
+In a Dockerfile, which use POSIX sh, we'll need to:
+
+```dockerfile
+# set GHJK_ENV for use
+ENV GHJK_ENV=ci
+ENV GHJK_ACTIVATE=.ghjk/envs/$GHJK_ENV/activate.sh
+# cook $GHJK_ENV
+RUN ghjk envs cook
+
+# each RUN command is a separate shell session
+# and requires explicit activation
+RUN source "$GHJK_ACTIVATE" \
+ && echo $MY_VAR
+```
+
+This extra boilerplate can be avoided by using the SHELL command available in some Dockerfile implementations or by using command processors more advanced that POSIX sh.
+
+```dockerfile
+# contraption to make sh load the activate script at startup
+SHELL ["/bin/sh", "-c", "source .ghjk/envs/my-env/activate.sh; sh -c $*", "sh"]
+RUN echo $MY_VAR
+```
+
+### Github action
+
+For users of Github CI, there's an action available on the [marketplace](https://github.com/marketplace/actions/ghjk-everything) that is able to:
+- Installs ghjk CLI and hooks
+- Caches the ghjk share directory
+- Cooks the `$GHJK_ENV` or default environment
+
+Note that the default shell used by github workflows is POSIX `sh`.
+It's necessary to switch over to the `bash` shell to have the hooks auto activate your environment.
+Otherwise, it's necessary to use the approach described in the section above.
+
+```yaml
+ my-job:
+ steps:
+ - uses: metatypedev/setup-ghjk@v1
+ - shell: bash # must use bash shell for auto activation
+ run: |
+ echo $GHJK_ENV
+```
diff --git a/examples/env_vars/ghjk.ts b/examples/env_vars/ghjk.ts
index e670d440..1d98f92c 100644
--- a/examples/env_vars/ghjk.ts
+++ b/examples/env_vars/ghjk.ts
@@ -16,6 +16,6 @@ const { env, task } = ghjk;
env("main")
.var("A", "A#STATIC")
- .var("C", ($) => $`echo C [$A, $B]`.text())
.var("B", () => "B#DYNAMIC")
+ .var("C", ($) => $`echo C [$A, $B]`.text())
.onEnter(task(($) => $`echo enter $A, $B, $C`));
diff --git a/examples/kitchen/ghjk.ts b/examples/kitchen/ghjk.ts
index a88897e4..ca2aa829 100644
--- a/examples/kitchen/ghjk.ts
+++ b/examples/kitchen/ghjk.ts
@@ -119,4 +119,5 @@ env("dev")
.onEnter(task({
workingDir: "..",
fn: ($) => $`ls`,
- }));
+ }))
+ .onExit(task(($) => $`echo exit`));
diff --git a/files/mod.ts b/files/mod.ts
index 44c03228..dc30b666 100644
--- a/files/mod.ts
+++ b/files/mod.ts
@@ -25,8 +25,7 @@ import {
unwrapZodRes,
} from "../utils/mod.ts";
import * as std_ports from "../modules/ports/std.ts";
-import * as cpy from "../ports/cpy_bs.ts";
-import * as node from "../ports/node.ts";
+import runtime_ports from "../modules/ports/std_runtime.ts";
// host
import type { SerializedConfig } from "../host/types.ts";
import * as std_modules from "../modules/std.ts";
@@ -1085,15 +1084,14 @@ export function stdDeps(args = { enableRuntimes: false }) {
if (args.enableRuntimes) {
out.push(
...reduceAllowedDeps([
- node.default(),
- cpy.default(),
+ ...runtime_ports,
]),
);
}
return out;
}
-function task$(
+export function task$(
argv: string[],
env: Record,
workingDir: string,
diff --git a/ghjk.ts b/ghjk.ts
index 3560a6ab..f18bba97 100644
--- a/ghjk.ts
+++ b/ghjk.ts
@@ -1,3 +1,5 @@
+// @ts-nocheck: Ghjkfile based on Deno
+
export { sophon } from "./hack.ts";
import { config, install, task } from "./hack.ts";
import * as ports from "./ports/mod.ts";
@@ -6,6 +8,7 @@ import { sedLock } from "./std.ts";
config({
defaultBaseEnv: "test",
enableRuntimes: true,
+ allowedBuildDeps: [ports.cpy_bs({ version: "3.12.7" })],
});
// these are just for quick testing
@@ -17,7 +20,7 @@ const DENO_VERSION = "1.44.2";
install(
ports.act(),
ports.pipi({ packageName: "pre-commit" })[0],
- ports.cpy_bs(),
+ ports.pipi({ packageName: "vale" })[0],
ports.deno_ghrel({ version: DENO_VERSION }),
);
@@ -39,6 +42,16 @@ task(
[/(GHJK_VERSION="\$\{GHJK_VERSION:-v).*(\}")/, GHJK_VERSION],
[/(DENO_VERSION="\$\{DENO_VERSION:-v).*(\}")/, DENO_VERSION],
],
+ "./docs/*.md": [
+ [
+ /(.*\/metatypedev\/ghjk\/v)[^/]*(\/.*)/,
+ GHJK_VERSION,
+ ],
+ [
+ /(GHJK_VERSION\s*=\s*v)[^\s]*(.*)/,
+ GHJK_VERSION,
+ ],
+ ],
"./README.md": [
[
/(.*\/metatypedev\/ghjk\/v)[^/]*(\/.*)/,
diff --git a/hack.ts b/hack.ts
index bb093358..3d2ebeb8 100644
--- a/hack.ts
+++ b/hack.ts
@@ -15,6 +15,7 @@ export const config = Object.freeze(firstCallerCheck(ghjk.config));
export const env = Object.freeze(firstCallerCheck(ghjk.env));
export const install = Object.freeze(firstCallerCheck(ghjk.install));
export const task = Object.freeze(firstCallerCheck(ghjk.task));
+export const tasks = Object.freeze(firstCallerCheck(ghjk.tasks));
// capture exit fn to avoid malicous caller from
// changing it on Deno object
diff --git a/host/init/mod.ts b/host/init/mod.ts
new file mode 100644
index 00000000..9e0727c2
--- /dev/null
+++ b/host/init/mod.ts
@@ -0,0 +1,182 @@
+import { DenoTaskDefArgs, task$ } from "../../files/mod.ts";
+import { zod } from "../../deps/common.ts";
+import {
+ findEntryRecursive,
+ importRaw,
+ Path,
+ unwrapZodRes,
+} from "../../utils/mod.ts";
+
+// NOTE: only limited subset of task featutres are avail.
+// no environments and deps
+const tasks: Record = {
+ "init-ts": {
+ desc: "Create a typescript ghjkfile in the current directory.",
+ async fn($, args) {
+ {
+ const ghjkdir = $.env["GHJK_DIR"] ??
+ await findEntryRecursive($.workingDir, ".ghjk");
+ if (ghjkdir) {
+ throw new Error(
+ "already in a ghjkdir context located at: ${ghjkdir}",
+ );
+ }
+ }
+ const ghjkFilePath = $.workingDir.join("ghjk.ts");
+ if (!await ghjkFilePath.exists()) {
+ const templatePath = import.meta.resolve("./template.ts");
+ const ghjkRoot = import.meta.resolve("../../");
+ const template = await importRaw(templatePath);
+ const final = template.replaceAll(
+ /from "..\/..\/(.*)"; \/\/ template-import/g,
+ `from "${ghjkRoot}$1";`,
+ );
+ await ghjkFilePath.writeText(final);
+ $.logger.info("written ghjk.ts to", ghjkFilePath);
+ await tasks["init-ts-lsp"].fn!($, args);
+ }
+ },
+ },
+ "init-ts-lsp": {
+ desc:
+ "Interactively configure working directory for best LSP support of ghjk.ts. Pass --yes to confirm every choice.",
+ async fn($) {
+ const all = $.argv[0] == "--yes";
+ const ghjkfile = $.env["GHJKFILE"] ?? "ghjk.ts";
+ const changeVscodeSettings = all || await $.confirm(
+ `Configure deno lsp to selectively enable on ${ghjkfile} through .vscode/settings.json?`,
+ {
+ default: true,
+ },
+ );
+ if (changeVscodeSettings) {
+ const vscodeSettingsRaw = await $.prompt(
+ "Path to .vscode/settings.json ghjk working dir",
+ {
+ default: ".vscode/settings.json",
+ },
+ );
+ await handleVscodeSettings(
+ $,
+ ghjkfile,
+ $.workingDir.join(vscodeSettingsRaw),
+ );
+ }
+ const ghjkfilePath = $.workingDir.join(ghjkfile);
+ if (await ghjkfilePath.exists()) {
+ const content = await ghjkfilePath.readText();
+ if (/@ts-nocheck/.test(content)) {
+ $.logger.info(`@ts-nocheck detected in ${ghjkfile}, skipping`);
+ return;
+ }
+ const changeGhjkts = await $.confirm(
+ `Mark ${ghjkfile} with @ts-nocheck`,
+ {
+ default: true,
+ },
+ );
+ if (changeGhjkts) {
+ await ghjkfilePath.writeText(`
+// @ts-nocheck: Ghjkfile based on Deno
+
+${content}`);
+ }
+ }
+ },
+ },
+};
+
+async function handleVscodeSettings(
+ $: ReturnType,
+ ghjkfile: string,
+ vscodeSettings: Path,
+) {
+ if (!await vscodeSettings.exists()) {
+ $.logger.error(
+ `No file detected at ${vscodeSettings}, creating a new one.`,
+ );
+ const config = {
+ "deno.enablePaths": [
+ ghjkfile,
+ ],
+ };
+ vscodeSettings.writeJsonPretty(config);
+ $.logger.info(`Wrote config to ${vscodeSettings}`, config);
+ return;
+ }
+
+ const schema = zod.object({
+ "deno.enablePaths": zod.string().array().optional(),
+ "deno.disablePaths": zod.string().array().optional(),
+ deno: zod.object({
+ enablePaths: zod.string().array().optional(),
+ disablePaths: zod.string().array().optional(),
+ }).passthrough().optional(),
+ }).passthrough();
+
+ const originalConfig = await vscodeSettings.readJson()
+ .catch((err) => {
+ throw new Error(`error parsing JSON at ${vscodeSettings}`, err);
+ });
+ const parsedConfig = unwrapZodRes(schema.safeParse(originalConfig), {
+ originalConfig,
+ }, "unexpected JSON discovored at .vscode/settings.json");
+
+ let writeOut = false;
+
+ if (parsedConfig["deno.enablePaths"]) {
+ if (!parsedConfig["deno.enablePaths"].includes(ghjkfile)) {
+ $.logger.info(
+ `Adding ${ghjkfile} to "deno.enablePaths"`,
+ );
+ parsedConfig["deno.enablePaths"].push(ghjkfile);
+ writeOut = true;
+ } else {
+ $.logger.info(
+ `Detected ${ghjkfile} in "deno.enablePaths", skipping`,
+ );
+ }
+ } else if (parsedConfig.deno?.enablePaths) {
+ if (!parsedConfig.deno.enablePaths.includes(ghjkfile)) {
+ $.logger.info(
+ `Adding ${ghjkfile} to deno.enablePaths`,
+ );
+ parsedConfig.deno.enablePaths.push(ghjkfile);
+ writeOut = true;
+ } else {
+ $.logger.info(
+ `Detected ${ghjkfile} in deno.enablePaths, skipping`,
+ );
+ }
+ } else if (parsedConfig["deno.disablePaths"]) {
+ if (parsedConfig["deno.disablePaths"].includes(ghjkfile)) {
+ throw new Error(
+ `${ghjkfile} detected in "deno.disablePaths". Confused :/`,
+ );
+ } else {
+ $.logger.info(
+ `No ${ghjkfile} in "deno.disablePaths", skipping`,
+ );
+ }
+ } else if (parsedConfig.deno?.disablePaths) {
+ if (parsedConfig.deno.disablePaths.includes(ghjkfile)) {
+ throw new Error(
+ `${ghjkfile} detected in deno.disablePaths. Confused :/`,
+ );
+ } else {
+ $.logger.info(
+ `No ${ghjkfile} in deno.disablePaths, skipping`,
+ );
+ }
+ } else {
+ parsedConfig["deno.enablePaths"] = [ghjkfile];
+ $.logger.info(
+ `Adding ${ghjkfile} to "deno.enablePaths"`,
+ );
+ }
+ if (writeOut) {
+ vscodeSettings.writeJsonPretty(parsedConfig);
+ $.logger.info(`Wrote config to ${vscodeSettings}`, parsedConfig);
+ }
+}
+export default tasks;
diff --git a/host/init/template.ts b/host/init/template.ts
new file mode 100644
index 00000000..fdf1460e
--- /dev/null
+++ b/host/init/template.ts
@@ -0,0 +1,22 @@
+// @ts-nocheck: Deno based
+
+import { file } from "../../mod.ts"; // template-import
+// import * as ports from "../../ports/mod.ts"; // template-import
+
+const ghjk = file({
+ // allows usage of ports that depend on node/python
+ // enableRuntimes: true,
+});
+
+// This export is necessary for ts ghjkfiles
+export const sophon = ghjk.sophon;
+
+ghjk.install(
+ // install ports into the main env
+ // ports.node(),
+ // ports.cpy_bs(),
+);
+
+ghjk.task("greet", async ($) => {
+ await $`echo Hello ${$.argv}`;
+});
diff --git a/host/mod.ts b/host/mod.ts
index 8a62b233..45149bf4 100644
--- a/host/mod.ts
+++ b/host/mod.ts
@@ -11,9 +11,11 @@ import {
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;
@@ -102,6 +104,26 @@ export async function cli(args: CliArgs) {
}
}
+ 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)
@@ -110,19 +132,8 @@ export async function cli(args: CliArgs) {
this.showHelp();
})
.command(
- "completions",
- new cliffy_cmd.CompletionsCommand(),
- )
- .command(
- "deno",
- new cliffy_cmd.Command()
- .description("Access the deno cli.")
- .useRawArgs()
- .action(async function (_, ...args) {
- logger().debug(args);
- await $.raw`${Deno.execPath()} ${args}`
- .env("DENO_EXEC_PATH", Deno.execPath());
- }),
+ "init",
+ initCmd,
)
.command(
"print",
@@ -158,7 +169,7 @@ export async function cli(args: CliArgs) {
.command(
"ghjkfile-path",
new cliffy_cmd.Command()
- .description("Print the path of the ghjk.ts used")
+ .description("Print the path of the ghjk.ts used.")
.action(function () {
if (!gcx?.ghjkfilePath) {
throw new Error("no ghjkfile found.");
@@ -171,7 +182,7 @@ export async function cli(args: CliArgs) {
"config",
new cliffy_cmd.Command()
.description(
- "Print the extracted ans serialized config from the ghjkfile",
+ "Print the extracted and serialized config from the ghjkfile.",
)
.option(
"--json",
@@ -189,10 +200,27 @@ export async function cli(args: CliArgs) {
);
}),
),
+ )
+ .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) {
@@ -313,14 +341,6 @@ async function commandsFromConfig(hcx: HostCtx, gcx: GhjkCtx) {
}
}
- if (
- !hcx.lockedFlagSet && wasReSerialized && (
- !foundHashObj || !deep_eql(newHashObj, foundHashObj)
- )
- ) {
- await hashFilePath.writeJsonPretty(newHashObj);
- }
-
// `writeLockFile` can be invoked multiple times
// so we keep track of the last lockfile wrote
// out to disk
@@ -358,6 +378,16 @@ async function commandsFromConfig(hcx: HostCtx, gcx: GhjkCtx) {
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);
+ }
},
};
}
diff --git a/install/mod.ts b/install/mod.ts
index d63eca51..32105067 100644
--- a/install/mod.ts
+++ b/install/mod.ts
@@ -201,15 +201,15 @@ export async function install(
}
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 installDir = await $.path(args.ghjkExecInstallDir).ensureDir();
const exePath = installDir.resolve(`ghjk`);
- logger.info("installing executable", { exePath });
+ logger.debug("installing executable", { exePath });
// use an isolated cache by default
const denoCacheDir = args.ghjkDenoCacheDir
@@ -244,6 +244,12 @@ export async function install(
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(),
+ );
}
logger.info("install success");
}
diff --git a/mod.ts b/mod.ts
index 891c777a..58ee37e7 100644
--- a/mod.ts
+++ b/mod.ts
@@ -51,6 +51,14 @@ export type AddTask = {
): string;
};
+/**
+ * Define and register multiple tasks.
+ */
+export type AddTasks = {
+ (args: (DenoTaskDefArgs | TaskFn)[]): string[];
+ (args: Record>): string[];
+};
+
export type FileArgs = {
/**
* The env to activate by default. When entering the working
@@ -111,6 +119,10 @@ type DenoFileKnobs = {
* {@inheritdoc AddTask}
*/
task: AddTask;
+ /**
+ * {@inheritdoc AddTasks}
+ */
+ tasks: AddTasks;
/**
* {@inheritDoc AddEnv}
*/
@@ -216,6 +228,34 @@ export const file = Object.freeze(function file(
),
});
+ function task(
+ nameOrArgsOrFn: string | DenoTaskDefArgs | TaskFn,
+ argsOrFn?: Omit | TaskFn,
+ argsMaybe?: Omit,
+ ) {
+ let args: DenoTaskDefArgs;
+ if (typeof nameOrArgsOrFn == "object") {
+ args = nameOrArgsOrFn;
+ } else if (typeof nameOrArgsOrFn == "function") {
+ args = {
+ ...(argsOrFn ?? {}),
+ fn: nameOrArgsOrFn,
+ };
+ } else if (typeof argsOrFn == "object") {
+ args = { ...argsOrFn, name: nameOrArgsOrFn };
+ } else if (argsOrFn) {
+ args = {
+ ...(argsMaybe ?? {}),
+ name: nameOrArgsOrFn,
+ fn: argsOrFn,
+ };
+ } else {
+ args = {
+ name: nameOrArgsOrFn,
+ };
+ }
+ return builder.addTask({ ...args, ty: "denoFile@v1" });
+ }
// we return a bunch of functions here
// to ease configuring the main environment
// including overloads
@@ -226,33 +266,18 @@ export const file = Object.freeze(function file(
mainEnv.install(...configs);
},
- task(
- nameOrArgsOrFn: string | DenoTaskDefArgs | TaskFn,
- argsOrFn?: Omit | TaskFn,
- argsMaybe?: Omit,
+ task,
+
+ tasks(
+ defs:
+ | (DenoTaskDefArgs | TaskFn)[]
+ | Record>,
) {
- let args: DenoTaskDefArgs;
- if (typeof nameOrArgsOrFn == "object") {
- args = nameOrArgsOrFn;
- } else if (typeof nameOrArgsOrFn == "function") {
- args = {
- ...(argsOrFn ?? {}),
- fn: nameOrArgsOrFn,
- };
- } else if (typeof argsOrFn == "object") {
- args = { ...argsOrFn, name: nameOrArgsOrFn };
- } else if (argsOrFn) {
- args = {
- ...(argsMaybe ?? {}),
- name: nameOrArgsOrFn,
- fn: argsOrFn,
- };
+ if (Array.isArray(defs)) {
+ return defs.map((def) => task(def));
} else {
- args = {
- name: nameOrArgsOrFn,
- };
+ return Object.entries(defs).map(([key, val]) => task(key, val));
}
- return builder.addTask({ ...args, ty: "denoFile@v1" });
},
env(
diff --git a/modules/envs/mod.ts b/modules/envs/mod.ts
index 6258f72b..516173b3 100644
--- a/modules/envs/mod.ts
+++ b/modules/envs/mod.ts
@@ -181,7 +181,7 @@ export class EnvsModule extends ModuleBase {
});
const env = ecx.config.envs[envKey];
if (!env) {
- throw new Error(`no env found under "${envKeyMaybe}"`);
+ throw new Error(`no env found under "${envKey}"`);
}
// deno-lint-ignore no-console
console.log($.inspect(await showableEnv(gcx, env, envKey)));
diff --git a/modules/envs/posix.ts b/modules/envs/posix.ts
index 5e775f50..5812f1f7 100644
--- a/modules/envs/posix.ts
+++ b/modules/envs/posix.ts
@@ -238,16 +238,25 @@ async function writeActivators(
`# shellcheck disable=SC2016`,
`# SC2016: disabled because single quoted expressions are used for the cleanup scripts`,
``,
- `if [ -n "$\{GHJK_CLEANUP_POSIX+x}" ]; then`,
- ` eval "$GHJK_CLEANUP_POSIX"`,
- `fi`,
- `export GHJK_CLEANUP_POSIX="";`,
+ `# this file bust be sourced from an existing sh/bash/zsh session using the \`source\` command`,
+ `# it cannot be executed directly`,
+ ``,
+ `ghjk_deactivate () {`,
+ ` if [ -n "$\{GHJK_CLEANUP_POSIX+x}" ]; then`,
+ ` eval "$GHJK_CLEANUP_POSIX"`,
+ ` unset GHJK_CLEANUP_POSIX`,
+ ` fi`,
+ `}`,
+ `ghjk_deactivate`,
+ ``,
``,
`# the following variables are used to make the script more human readable`,
`${ghjkDirVar}="${gcx.ghjkDir.toString()}"`,
`${shareDirVar}="${gcx.ghjkShareDir.toString()}"`,
``,
`# env vars`,
+ `# we keep track of old values before this script is run`,
+ `# so that we can restore them on cleanup`,
...Object.entries(envVars).flatMap(([key, val]) => {
const safeVal = val.replaceAll("\\", "\\\\").replaceAll("'", "'\\''");
// avoid triggering unbound variable if -e is set
@@ -273,7 +282,7 @@ async function writeActivators(
// i.e. export KEY='OLD $VALUE OF KEY'
// but $VALUE won't be expanded when the cleanup actually runs
// we also unset the key if it wasn't previously set
- `$([ -z "$\{${key}+x}" ] && echo 'export ${key}= '\\'"$\{${key}:-unreachable}""';" || echo 'unset ${key};');`,
+ `$([ -z "$\{${key}+x}" ] && echo 'export ${key}='\\'"$\{${key}:-unreachable}""';" || echo 'unset ${key};');`,
`export ${key}='${safeVal}';`,
``,
];
@@ -295,7 +304,7 @@ async function writeActivators(
}),
``,
`# hooks that want to invoke ghjk are made to rely`,
- `# on this shim to improving latency`,
+ `# on this shim instead to improve latency`,
// the ghjk executable is itself a shell script
// which execs deno, we remove the middleman here
// also, the ghjk executable is optional
@@ -323,25 +332,33 @@ async function writeActivators(
//
// fish version
fish: [
- `if set --query GHJK_CLEANUP_FISH`,
- ` eval $GHJK_CLEANUP_FISH`,
- ` set --erase GHJK_CLEANUP_FISH`,
+ `# this file bust be sourced from an existing fish session using the \`source\` command`,
+ `# it cannot be executed directly`,
+ ``,
+ `function ghjk_deactivate`,
+ ` if set --query GHJK_CLEANUP_FISH`,
+ ` eval $GHJK_CLEANUP_FISH`,
+ ` set --erase GHJK_CLEANUP_FISH`,
+ ` end`,
`end`,
+ `ghjk_deactivate`,
``,
`# the following variables are used to make the script more human readable`,
`set ${ghjkDirVar} "${gcx.ghjkDir.toString()}"`,
`set ${shareDirVar} "${gcx.ghjkShareDir.toString()}"`,
``,
`# env vars`,
+ `# we keep track of old values before this script is run`,
+ `# so that we can restore them on cleanup`,
...Object.entries(envVars).flatMap(([key, val]) => {
const safeVal = val.replaceAll("\\", "\\\\").replaceAll("'", "\\'");
// read the comments from the posix version of this section
// the fish version is notably simpler since
- // - we can escape single quates within single quotes
+ // - we can escape single quotes within single quotes
// - we don't have to deal with 'set -o nounset'
return [
`set --global --append GHJK_CLEANUP_FISH 'test "$${key}" = \\'${safeVal}\\'; and '` +
- `(if set -q ${key}; echo 'set --global --export ${key} \\'' "$${key}" "';"; else; echo 'set -e ${key};'; end;);`,
+ `(if set -q ${key}; echo 'set --global --export ${key} \\''"$${key}""';"; else; echo 'set -e ${key};'; end;);`,
`set --global --export ${key} '${val}';`,
``,
];
@@ -358,7 +375,7 @@ async function writeActivators(
}),
``,
`# hooks that want to invoke ghjk are made to rely`,
- `# on this shim to improving latency`,
+ `# on this shim to improve latency`,
ghjk_fish(gcx, denoDir, ghjkShimName),
``,
`# only run the hooks in interactive mode`,
diff --git a/modules/ports/ambient.ts b/modules/ports/ambient.ts
index 6b290535..80031363 100644
--- a/modules/ports/ambient.ts
+++ b/modules/ports/ambient.ts
@@ -12,7 +12,7 @@ export class AmbientAccessPort extends PortBase {
);
}
}
- async latestStable() {
+ override async latestStable() {
const execPath = await this.pathToExec();
let versionOut;
try {
@@ -44,11 +44,11 @@ export class AmbientAccessPort extends PortBase {
return [await this.latestStable()];
}
- async listBinPaths(): Promise {
+ override async listBinPaths(): Promise {
return [await this.pathToExec()];
}
- async download() {
+ override async download() {
// no op
}
diff --git a/modules/ports/ghrel.ts b/modules/ports/ghrel.ts
index a15a6e55..6b7f27b6 100644
--- a/modules/ports/ghrel.ts
+++ b/modules/ports/ghrel.ts
@@ -50,7 +50,7 @@ export abstract class GithubReleasePort extends PortBase {
return [];
}
- async download(args: DownloadArgs): Promise {
+ override async download(args: DownloadArgs): Promise {
const urls = await this.downloadUrls(args);
if (urls.length == 0) {
throw new Error(
@@ -65,7 +65,7 @@ export abstract class GithubReleasePort extends PortBase {
);
}
- async latestStable(args: ListAllArgs) {
+ override async latestStable(args: ListAllArgs) {
const metadata = await $.withRetries({
count: 10,
delay: $.exponentialBackoff(1000),
diff --git a/modules/ports/mod.ts b/modules/ports/mod.ts
index 382b82d4..1dcad40d 100644
--- a/modules/ports/mod.ts
+++ b/modules/ports/mod.ts
@@ -141,7 +141,7 @@ export class PortsModule extends ModuleBase {
.command(
"outdated",
new cliffy_cmd.Command()
- .description("Show a version table for installs")
+ .description("Show a version table for installs.")
.option(
"-u, --update-install ",
"Update specific install",
diff --git a/modules/ports/std.ts b/modules/ports/std.ts
index a6388490..134efdfd 100644
--- a/modules/ports/std.ts
+++ b/modules/ports/std.ts
@@ -1,5 +1,6 @@
//! This plugin exports the list of standard ports other
-//! plugins are allowed to depend on.
+//! plugins are expected to depend on.
+
import validators, {
type AllowedPortDepX,
type PortDep,
@@ -12,7 +13,6 @@ import { manifest as man_git_aa } from "../../ports/git.ts";
import { manifest as man_curl_aa } from "../../ports/curl.ts";
import { manifest as man_cbin_ghrel } from "../../ports/cargo-binstall.ts";
import { manifest as man_node_org } from "../../ports/node.ts";
-import { manifest as man_pnpm_ghrel } from "../../ports/pnpm.ts";
import { manifest as man_asdf_plugin_git } from "../../ports/asdf_plugin_git.ts";
import { manifest as man_cpy_bs_ghrel } from "../../ports/cpy_bs.ts";
import { manifest as man_rustup_rustlang } from "../../ports/rustup.ts";
@@ -29,14 +29,16 @@ const aaPorts: PortManifest[] = [
const denoPorts: PortManifest[] = [
man_rustup_rustlang,
- man_rust_rustup,
man_cbin_ghrel,
- man_pnpm_ghrel,
- man_asdf_plugin_git,
+ // man_asdf_plugin_git,
+ // man_rust_rustup,
// man_cpy_bs_ghrel,
// man_node_org,
];
+/**
+ * The default set of allowed port deps.
+ */
const defaultAllowedDeps: AllowedPortDepX[] = [
...aaPorts,
...denoPorts,
@@ -91,10 +93,6 @@ export const node_org = Object.freeze({
name: man_node_org.name,
} as PortDep);
-export const pnpm_ghrel = Object.freeze({
- name: man_pnpm_ghrel.name,
-} as PortDep);
-
export const cpy_bs_ghrel = Object.freeze({
name: man_cpy_bs_ghrel.name,
} as PortDep);
diff --git a/modules/ports/std_runtime.ts b/modules/ports/std_runtime.ts
new file mode 100644
index 00000000..58f0753a
--- /dev/null
+++ b/modules/ports/std_runtime.ts
@@ -0,0 +1,17 @@
+//! The list of ports enabled when enableRuntimes is used on a ghjkfile configuration.
+
+import * as cpy_bs from "../../ports/cpy_bs.ts";
+import * as node from "../../ports/node.ts";
+import * as rust from "../../ports/rust.ts";
+import * as asdf_plugin_git from "../../ports/asdf_plugin_git.ts";
+
+export default [
+ // commonly used by the npmi port for installation using npm
+ node.default(),
+ // commonly used by the pipi port for installation using pip
+ cpy_bs.default(),
+ // commonly used by the cargobi port for building crates
+ rust.default(),
+ // used by the asdf port for installing asdf plugins
+ asdf_plugin_git.buildDep(),
+];
diff --git a/modules/ports/worker.ts b/modules/ports/worker.ts
index 5437aa74..de2a21c8 100644
--- a/modules/ports/worker.ts
+++ b/modules/ports/worker.ts
@@ -201,7 +201,7 @@ export class DenoWorkerPort extends PortBase {
throw new Error(`unexpected response from worker ${JSON.stringify(res)}`);
}
- async latestStable(env: ListAllArgs) {
+ override async latestStable(env: ListAllArgs) {
const req: WorkerReq = {
ty: "latestStable",
arg: env,
@@ -214,7 +214,7 @@ export class DenoWorkerPort extends PortBase {
throw new Error(`unexpected response from worker ${JSON.stringify(res)}`);
}
- async execEnv(
+ override async execEnv(
args: ExecEnvArgs,
) {
const req: WorkerReq = {
@@ -228,7 +228,7 @@ export class DenoWorkerPort extends PortBase {
}
throw new Error(`unexpected response from worker ${JSON.stringify(res)}`);
}
- async listBinPaths(
+ override async listBinPaths(
args: ListBinPathsArgs,
) {
const req: WorkerReq = {
@@ -243,7 +243,7 @@ export class DenoWorkerPort extends PortBase {
throw new Error(`unexpected response from worker ${JSON.stringify(res)}`);
}
- async listLibPaths(
+ override async listLibPaths(
args: ListBinPathsArgs,
) {
const req: WorkerReq = {
@@ -258,7 +258,7 @@ export class DenoWorkerPort extends PortBase {
throw new Error(`unexpected response from worker ${JSON.stringify(res)}`);
}
- async listIncludePaths(
+ override async listIncludePaths(
args: ListBinPathsArgs,
) {
const req: WorkerReq = {
@@ -273,7 +273,7 @@ export class DenoWorkerPort extends PortBase {
throw new Error(`unexpected response from worker ${JSON.stringify(res)}`);
}
- async download(args: DownloadArgs) {
+ override async download(args: DownloadArgs) {
const req: WorkerReq = {
ty: "download",
arg: args,
@@ -285,7 +285,7 @@ export class DenoWorkerPort extends PortBase {
}
throw new Error(`unexpected response from worker ${JSON.stringify(res)}`);
}
- async install(args: InstallArgs) {
+ override async install(args: InstallArgs) {
const req: WorkerReq = {
ty: "install",
arg: args,
diff --git a/modules/tasks/mod.ts b/modules/tasks/mod.ts
index 7c87f7ff..222bda79 100644
--- a/modules/tasks/mod.ts
+++ b/modules/tasks/mod.ts
@@ -85,7 +85,9 @@ export class TasksModule extends ModuleBase {
.action(function () {
this.showHelp();
})
- .description("Tasks module.");
+ .description(`Tasks module.
+
+The named tasks in your ghjkfile will be listed here.`);
for (const cmd of commands) {
root.command(cmd.getName(), cmd);
}
diff --git a/ports/act.ts b/ports/act.ts
index 019f2362..9d947403 100644
--- a/ports/act.ts
+++ b/ports/act.ts
@@ -33,7 +33,7 @@ export class Port extends GithubReleasePort {
repoOwner = "nektos";
repoName = "act";
- downloadUrls(args: DownloadArgs) {
+ override downloadUrls(args: DownloadArgs) {
const { installVersion, platform } = args;
let arch;
switch (platform.arch) {
@@ -73,7 +73,7 @@ export class Port extends GithubReleasePort {
].map(dwnUrlOut);
}
- async install(args: InstallArgs) {
+ override async install(args: InstallArgs) {
const [{ name: fileName }] = this.downloadUrls(args);
const fileDwnPath = std_path.resolve(args.downloadPath, fileName);
diff --git a/ports/asdf.ts b/ports/asdf.ts
index f32d8daf..c0bfd14e 100644
--- a/ports/asdf.ts
+++ b/ports/asdf.ts
@@ -72,7 +72,7 @@ export class Port extends PortBase {
return out.split(/\s/).filter(Boolean).map((str) => str.trim());
}
- async latestStable(args: ListAllArgs) {
+ override async latestStable(args: ListAllArgs) {
const binPath = tryDepExecShimPath(
std_ports.asdf_plugin_git,
"latest-stable",
@@ -93,7 +93,7 @@ export class Port extends PortBase {
return out.trim();
}
- async listBinPaths(args: ListBinPathsArgs) {
+ override async listBinPaths(args: ListBinPathsArgs) {
const binPath = tryDepExecShimPath(
std_ports.asdf_plugin_git,
"list-bin-paths",
@@ -113,7 +113,7 @@ export class Port extends PortBase {
return out.split(/\s/).filter(Boolean).map((str) => str.trim());
}
- async download(args: DownloadArgs) {
+ override async download(args: DownloadArgs) {
// some plugins don't have a download script despite the spec
const binPath = tryDepExecShimPath(
std_ports.asdf_plugin_git,
@@ -134,7 +134,7 @@ export class Port extends PortBase {
ASDF_DOWNLOAD_PATH: args.downloadPath,
});
}
- async install(args: InstallArgs) {
+ override async install(args: InstallArgs) {
const conf = confValidator.parse(args.config);
await $`${
depExecShimPath(std_ports.asdf_plugin_git, "install", args.depArts)
diff --git a/ports/asdf_plugin_git.ts b/ports/asdf_plugin_git.ts
index 60bc7669..ab7c4458 100644
--- a/ports/asdf_plugin_git.ts
+++ b/ports/asdf_plugin_git.ts
@@ -1,8 +1,10 @@
import {
$,
+ AllowedPortDep,
defaultLatestStable,
depExecShimPath,
type DownloadArgs,
+ getPortRef,
type InstallArgs,
type InstallConfigSimple,
type ListAllArgs,
@@ -35,6 +37,13 @@ export type AsdfPluginInstallConf =
& InstallConfigSimple
& zod.input;
+/**
+ * WARNING: this is probably no the function you want if you intend
+ * to add `asdf_plugin_git` to your `allowedBuildDeps`.
+ *
+ * This module exports a {@link buildDep} function for the purpose of adding
+ * the port to the allowedBuildDeps list.
+ */
export default function conf(config: AsdfPluginInstallConf) {
return {
...confValidator.parse(config),
@@ -42,6 +51,15 @@ export default function conf(config: AsdfPluginInstallConf) {
};
}
+export function buildDep(): AllowedPortDep {
+ return {
+ manifest,
+ defaultInst: {
+ portRef: getPortRef(manifest),
+ },
+ };
+}
+
export class Port extends PortBase {
async listAll(args: ListAllArgs) {
const conf = confValidator.parse(args.config);
@@ -55,11 +73,11 @@ export class Port extends PortBase {
.map((line) => line.split(/\s/)[0].slice(0, 10));
}
- latestStable(args: ListAllArgs): Promise {
+ override latestStable(args: ListAllArgs): Promise {
return defaultLatestStable(this, args);
}
- async download(args: DownloadArgs) {
+ override async download(args: DownloadArgs) {
if (await $.path(args.downloadPath).exists()) {
// FIXME: remove this once download tracking is part of core
return;
@@ -74,7 +92,7 @@ export class Port extends PortBase {
);
}
- async install(args: InstallArgs) {
+ override async install(args: InstallArgs) {
const tmpPath = $.path(args.tmpDirPath);
// we copy the repo to a src dir
const srcDir = (await tmpPath.ensureDir()).join("src");
diff --git a/ports/cargo-binstall.ts b/ports/cargo-binstall.ts
index 9c594dca..ff8744bb 100644
--- a/ports/cargo-binstall.ts
+++ b/ports/cargo-binstall.ts
@@ -33,7 +33,7 @@ export class Port extends GithubReleasePort {
repoOwner = "cargo-bins";
repoName = "cargo-binstall";
- downloadUrls(
+ override downloadUrls(
args: DownloadArgs,
) {
const { installVersion, platform } = args;
@@ -68,7 +68,7 @@ export class Port extends GithubReleasePort {
].map(dwnUrlOut);
}
- async install(args: InstallArgs) {
+ override async install(args: InstallArgs) {
const [{ name: fileName }] = this.downloadUrls(args);
const fileDwnPath = std_path.resolve(args.downloadPath, fileName);
diff --git a/ports/cargobi.ts b/ports/cargobi.ts
index 845bb078..fb3d4683 100644
--- a/ports/cargobi.ts
+++ b/ports/cargobi.ts
@@ -101,11 +101,11 @@ export class Port extends PortBase {
return versions.map((ver) => ver.vers);
}
- latestStable(args: ListAllArgs): Promise {
+ override latestStable(args: ListAllArgs): Promise {
return defaultLatestStable(this, args);
}
- async download(args: DownloadArgs) {
+ override async download(args: DownloadArgs) {
const conf = confValidator.parse(args.config);
const fileName = conf.crateName;
if (await std_fs.exists(std_path.resolve(args.downloadPath, fileName))) {
@@ -181,7 +181,7 @@ export class Port extends PortBase {
);
}
- async install(args: InstallArgs) {
+ override async install(args: InstallArgs) {
const installPath = $.path(args.installPath);
if (await installPath.exists()) {
await installPath.remove({ recursive: true });
diff --git a/ports/cmake.ts b/ports/cmake.ts
index 99fcea11..979bc722 100644
--- a/ports/cmake.ts
+++ b/ports/cmake.ts
@@ -9,20 +9,17 @@ import * as ports from "./mod.ts";
* For macOS users, you need to add python as allowed build dependencies
* as cmake is downladed via pip install.
*
- * Example:
+ * For other platforms, the `asdf_plugin_git` build dependency is required.
+ *
+ * Set the `enableRuntimes` flag to setup both cases.
+ *
* ```typescript
- * const installs = {
- python_latest: ports.cpy_bs({ version: "3.12.2", releaseTag: "20240224" }),
-};
- * config({
- stdDeps: true,
- allowedBuildDeps: [
- installs.python_latest
- ],
- enableRuntimes: true
-});
- * ```
+ * ghjk.config({
+ * enableRuntimes: true,
+ * });
*
+ * ghjk.install(ports.cmake());
+ * ```
*/
export default function conf(
config: InstallConfigSimple = {},
diff --git a/ports/cpy_bs.ts b/ports/cpy_bs.ts
index 3c19603c..89d7caa2 100644
--- a/ports/cpy_bs.ts
+++ b/ports/cpy_bs.ts
@@ -61,7 +61,7 @@ export default function conf(
export class Port extends PortBase {
repoOwner = "indygreg";
repoName = "python-build-standalone";
- execEnv(
+ override execEnv(
args: PortArgsBase,
): Record | Promise> {
return {
@@ -136,7 +136,7 @@ export class Port extends PortBase {
.sort((va, vb) => va.localeCompare(vb, undefined, { numeric: true }));
}
- async download(args: DownloadArgs) {
+ override async download(args: DownloadArgs) {
const headers = ghHeaders(args.config);
const conf = confValidator.parse(args.config);
let tag = conf.releaseTag;
@@ -176,7 +176,7 @@ export class Port extends PortBase {
);
}
- async install(args: InstallArgs) {
+ override async install(args: InstallArgs) {
const [_, fileDwnEntry] = await Array.fromAsync(
$.path(args.downloadPath).walk(),
);
diff --git a/ports/deno_ghrel.ts b/ports/deno_ghrel.ts
index 9da0d050..2a70df4d 100644
--- a/ports/deno_ghrel.ts
+++ b/ports/deno_ghrel.ts
@@ -35,7 +35,7 @@ export class Port extends GithubReleasePort {
repoOwner = "denoland";
repoName = "deno";
- downloadUrls(args: DownloadArgs) {
+ override downloadUrls(args: DownloadArgs) {
const { installVersion, platform } = args;
const arch = platform.arch;
let os;
@@ -60,7 +60,7 @@ export class Port extends GithubReleasePort {
].map(dwnUrlOut);
}
- async install(args: InstallArgs) {
+ override async install(args: InstallArgs) {
const [{ name: fileName }] = this.downloadUrls(args);
const fileDwnPath = std_path.resolve(args.downloadPath, fileName);
diff --git a/ports/dummy.ts b/ports/dummy.ts
index 8ba1dfcd..8ea5c9cc 100644
--- a/ports/dummy.ts
+++ b/ports/dummy.ts
@@ -39,7 +39,7 @@ export default function conf(config: DummyInstallConf = {}) {
}
export class Port extends PortBase {
- execEnv() {
+ override execEnv() {
return {
DUMMY_ENV: "dummy",
};
@@ -49,7 +49,7 @@ export class Port extends PortBase {
return ["dummy"];
}
- async download(args: DownloadArgs) {
+ override async download(args: DownloadArgs) {
const conf = confValidator.parse(args.config);
// TODO: windows suport
await $.path(args.downloadPath).join("bin", "dummy").writeText(
@@ -61,7 +61,7 @@ echo ${conf.output ?? "dummy hey"}`,
);
}
- async install(args: InstallArgs) {
+ override async install(args: InstallArgs) {
const installPath = $.path(args.installPath);
await $.removeIfExists(installPath);
await std_fs.copy(args.downloadPath, args.installPath);
diff --git a/ports/earthly.ts b/ports/earthly.ts
index fa41da87..b85c331b 100644
--- a/ports/earthly.ts
+++ b/ports/earthly.ts
@@ -31,7 +31,7 @@ export class Port extends GithubReleasePort {
repoOwner = "earthly";
repoName = "earthly";
- downloadUrls(args: DownloadArgs) {
+ override downloadUrls(args: DownloadArgs) {
const { installVersion, platform } = args;
let arch;
switch (platform.arch) {
@@ -57,7 +57,7 @@ export class Port extends GithubReleasePort {
];
}
- async install(args: InstallArgs) {
+ override async install(args: InstallArgs) {
const installPath = $.path(args.installPath);
if (await installPath.exists()) {
await installPath.remove({ recursive: true });
diff --git a/ports/infisical.ts b/ports/infisical.ts
index 8667c83d..917df6b6 100644
--- a/ports/infisical.ts
+++ b/ports/infisical.ts
@@ -43,12 +43,12 @@ export class Port extends GithubReleasePort {
const all = await super.listAll(args);
return all.map((str) => str.replace(/^infisical-cli\/v/, ""));
}
- async latestStable(args: ListAllArgs) {
+ override async latestStable(args: ListAllArgs) {
const lsv = await super.latestStable(args);
return lsv.replace(/^infisical-cli\/v/, "");
}
- downloadUrls(args: DownloadArgs) {
+ override downloadUrls(args: DownloadArgs) {
const { installVersion, platform } = args;
let arch;
switch (platform.arch) {
@@ -84,7 +84,7 @@ export class Port extends GithubReleasePort {
].map(dwnUrlOut);
}
- async install(args: InstallArgs) {
+ override async install(args: InstallArgs) {
const [{ name: fileName }] = this.downloadUrls(args);
const fileDwnPath = std_path.resolve(args.downloadPath, fileName);
diff --git a/ports/jq_ghrel.ts b/ports/jq_ghrel.ts
index 27fa2674..e84fe915 100644
--- a/ports/jq_ghrel.ts
+++ b/ports/jq_ghrel.ts
@@ -38,7 +38,7 @@ export class Port extends GithubReleasePort {
repoOwner = "jqlang";
repoName = "jq";
- downloadUrls(args: DownloadArgs) {
+ override downloadUrls(args: DownloadArgs) {
const { installVersion, platform } = args;
let arch;
@@ -64,7 +64,7 @@ export class Port extends GithubReleasePort {
.map((out) => ({ ...out, mode: 0o700 }));
}
- async install(args: InstallArgs) {
+ override async install(args: InstallArgs) {
const installPath = $.path(args.installPath);
await $.removeIfExists(installPath);
diff --git a/ports/meta_cli_ghrel.ts b/ports/meta_cli_ghrel.ts
index 97e6c696..3386852c 100644
--- a/ports/meta_cli_ghrel.ts
+++ b/ports/meta_cli_ghrel.ts
@@ -49,7 +49,7 @@ export class Port extends GithubReleasePort {
repoOwner = "metatypedev";
repoName = "metatype";
- downloadUrls(args: DownloadArgs) {
+ override downloadUrls(args: DownloadArgs) {
const conf = confValidator.parse(args.config);
const { installVersion, platform } = args;
let arch;
@@ -88,7 +88,7 @@ export class Port extends GithubReleasePort {
].map(dwnUrlOut);
}
- async install(args: InstallArgs) {
+ override async install(args: InstallArgs) {
const [{ name: fileName }] = this.downloadUrls(args);
const fileDwnPath = std_path.resolve(args.downloadPath, fileName);
diff --git a/ports/mod.ts b/ports/mod.ts
index d2833cd6..8e21ba3a 100644
--- a/ports/mod.ts
+++ b/ports/mod.ts
@@ -1,5 +1,6 @@
export { default as act } from "./act.ts";
export { default as asdf } from "./asdf.ts";
+export { default as asdf_plugin_git } from "./asdf_plugin_git.ts";
export { default as cargo_binstall } from "./cargo-binstall.ts";
export { default as cargobi } from "./cargobi.ts";
export { default as cmake } from "./cmake.ts";
diff --git a/ports/mold.ts b/ports/mold.ts
index 3d0f7ce9..345b1869 100644
--- a/ports/mold.ts
+++ b/ports/mold.ts
@@ -44,7 +44,7 @@ export class Port extends GithubReleasePort {
repoOwner = "rui314";
repoName = "mold";
- downloadUrls(args: DownloadArgs) {
+ override downloadUrls(args: DownloadArgs) {
const { installVersion, platform } = args;
const os = platform.os;
@@ -62,7 +62,7 @@ export class Port extends GithubReleasePort {
].map(dwnUrlOut);
}
- async install(args: InstallArgs) {
+ override async install(args: InstallArgs) {
const [{ name: fileName }] = this.downloadUrls(args);
const fileDwnPath = std_path.resolve(args.downloadPath, fileName);
diff --git a/ports/node.ts b/ports/node.ts
index 23405ab6..0cad73e9 100644
--- a/ports/node.ts
+++ b/ports/node.ts
@@ -44,19 +44,19 @@ export default function conf(config: InstallConfigSimple = {}) {
}
export class Port extends PortBase {
- execEnv(args: ExecEnvArgs) {
+ override execEnv(args: ExecEnvArgs) {
return {
NODE_PATH: args.installPath,
};
}
- latestStable(args: ListAllArgs): Promise {
+ override latestStable(args: ListAllArgs): Promise {
return defaultLatestStable(this, args);
}
// we wan't to avoid adding libraries found by default at /lib
// to PATHs as they're just node_module sources
- listLibPaths(): string[] {
+ override listLibPaths(): string[] {
return [];
}
@@ -109,14 +109,14 @@ export class Port extends PortBase {
].map(dwnUrlOut);
}
- async download(args: DownloadArgs) {
+ override async download(args: DownloadArgs) {
const urls = this.downloadUrls(args);
await Promise.all(
urls.map((obj) => downloadFile({ ...args, ...obj })),
);
}
- async install(args: InstallArgs) {
+ override async install(args: InstallArgs) {
const [{ name: fileName }] = this.downloadUrls(args);
const fileDwnPath = std_path.resolve(args.downloadPath, fileName);
diff --git a/ports/npmi.ts b/ports/npmi.ts
index b05ba128..fa61b996 100644
--- a/ports/npmi.ts
+++ b/ports/npmi.ts
@@ -81,7 +81,7 @@ export class Port extends PortBase {
return versions;
}
- async download(args: DownloadArgs) {
+ override async download(args: DownloadArgs) {
const conf = confValidator.parse(args.config);
await $.raw`${
depExecShimPath(std_ports.node_org, "npm", args.depArts)
@@ -93,7 +93,7 @@ export class Port extends PortBase {
// FIXME: replace shebangs with the runtime dep node path
// default shebangs just use #!/bin/env node
- async install(args: InstallArgs) {
+ override async install(args: InstallArgs) {
const conf = confValidator.parse(args.config);
await std_fs.copy(
args.downloadPath,
diff --git a/ports/opentofu_ghrel.ts b/ports/opentofu_ghrel.ts
index 8cd9c5e6..98aebc4c 100644
--- a/ports/opentofu_ghrel.ts
+++ b/ports/opentofu_ghrel.ts
@@ -37,7 +37,7 @@ export class Port extends GithubReleasePort {
repoOwner = "opentofu";
repoName = "opentofu";
- downloadUrls(args: DownloadArgs) {
+ override downloadUrls(args: DownloadArgs) {
const { installVersion, platform } = args;
let arch;
@@ -65,7 +65,7 @@ export class Port extends GithubReleasePort {
].map(dwnUrlOut);
}
- async install(args: InstallArgs) {
+ override async install(args: InstallArgs) {
const [{ name: fileName }] = this.downloadUrls(args);
const fileDwnPath = std_path.resolve(args.downloadPath, fileName);
diff --git a/ports/pipi.ts b/ports/pipi.ts
index 72992799..7669f274 100644
--- a/ports/pipi.ts
+++ b/ports/pipi.ts
@@ -62,12 +62,12 @@ export class Port extends PortBase {
return metadata.versions;
}
- latestStable(args: ListAllArgs): Promise {
+ override latestStable(args: ListAllArgs): Promise {
return defaultLatestStable(this, args);
}
// this creates the venv and install the package into it
- async download(args: DownloadArgs) {
+ override async download(args: DownloadArgs) {
const downloadPath = $.path(args.downloadPath);
if (await downloadPath.exists()) {
return;
@@ -142,7 +142,7 @@ export class Port extends PortBase {
// this modifies the venv so that it works with ghjk
// and exposes the packages and only the package's console scripts
- async install(args: InstallArgs) {
+ override async install(args: InstallArgs) {
const tmpPath = $.path(args.tmpDirPath);
const conf = confValidator.parse(args.config);
@@ -202,7 +202,7 @@ export class Port extends PortBase {
.map((execPath) =>
Deno.symlink(
// create a relative symlink
- // TODO: open ticket on dsherret/tax about createSymlinkTo(relative) bug
+ // TODO: open ticket on dsherret/jax about createSymlinkTo(relative) bug
".." + execPath.slice(tmpPath.toString().length),
tmpPath
.join("bin", $.path(execPath).basename()).toString(),
diff --git a/ports/pnpm.ts b/ports/pnpm.ts
index 353c661e..24a83e35 100644
--- a/ports/pnpm.ts
+++ b/ports/pnpm.ts
@@ -31,7 +31,7 @@ export class Port extends GithubReleasePort {
repoOwner = "pnpm";
repoName = "pnpm";
- downloadUrls(args: DownloadArgs) {
+ override downloadUrls(args: DownloadArgs) {
const { installVersion, platform } = args;
let arch;
let os;
@@ -74,7 +74,7 @@ export class Port extends GithubReleasePort {
];
}
- async install(args: InstallArgs) {
+ override async install(args: InstallArgs) {
const [{ name: fileName }] = this.downloadUrls(args);
const installPath = $.path(args.installPath);
diff --git a/ports/poetry.ts b/ports/poetry.ts
index 9b68ae70..b28de019 100644
--- a/ports/poetry.ts
+++ b/ports/poetry.ts
@@ -53,14 +53,14 @@ export class Port extends PipiPort {
return super.listAll({ ...args, config: toPipiConfig(args.config) });
}
- latestStable(args: ListAllArgs): Promise {
+ override latestStable(args: ListAllArgs): Promise {
return defaultLatestStable(this, {
...args,
config: toPipiConfig(args.config),
});
}
- download(args: DownloadArgs) {
+ override download(args: DownloadArgs) {
return super.download({ ...args, config: toPipiConfig(args.config) });
}
diff --git a/ports/protoc.ts b/ports/protoc.ts
index 67b28ac4..e6ea1729 100644
--- a/ports/protoc.ts
+++ b/ports/protoc.ts
@@ -33,7 +33,7 @@ export class Port extends GithubReleasePort {
repoOwner = "protocolbuffers";
repoName = "protobuf";
- downloadUrls(args: DownloadArgs) {
+ override downloadUrls(args: DownloadArgs) {
const { installVersion, platform } = args;
let os;
switch (platform.os) {
@@ -66,7 +66,7 @@ export class Port extends GithubReleasePort {
].map(dwnUrlOut);
}
- async install(args: InstallArgs) {
+ override async install(args: InstallArgs) {
const [{ name: fileName }] = this.downloadUrls(args);
const fileDwnPath = $.path(args.downloadPath).join(fileName);
diff --git a/ports/ruff.ts b/ports/ruff.ts
index 87aa0c7f..fa1d75d2 100644
--- a/ports/ruff.ts
+++ b/ports/ruff.ts
@@ -41,7 +41,7 @@ export class Port extends GithubReleasePort {
repoOwner = "astral-sh";
repoName = "ruff";
- downloadUrls(args: DownloadArgs) {
+ override downloadUrls(args: DownloadArgs) {
const { installVersion, platform } = args;
let arch;
switch (platform.arch) {
@@ -89,7 +89,7 @@ export class Port extends GithubReleasePort {
].map(dwnUrlOut);
}
- async install(args: InstallArgs) {
+ override async install(args: InstallArgs) {
const [{ name: fileName }] = this.downloadUrls(args);
const fileDwnPath = std_path.resolve(args.downloadPath, fileName);
diff --git a/ports/rust.ts b/ports/rust.ts
index 2819f8bf..5d34b6dd 100644
--- a/ports/rust.ts
+++ b/ports/rust.ts
@@ -128,13 +128,13 @@ export class Port extends PortBase {
return versions;
}
- async latestStable(args: ListAllArgs) {
+ override async latestStable(args: ListAllArgs) {
const versions = await this.listAll(args);
// stable releases are just version numbers, no
return versions.findLast((ver) => !ver.match(/[a-zA-Z]/))!;
}
- async download(args: DownloadArgs) {
+ override async download(args: DownloadArgs) {
const conf = confValidator.parse(args.config);
const tmpPath = $.path(args.tmpDirPath);
@@ -159,7 +159,7 @@ export class Port extends PortBase {
);
}
- async install(args: InstallArgs) {
+ override async install(args: InstallArgs) {
const installPath = $.path(args.installPath);
if (await installPath.exists()) {
await installPath.remove({ recursive: true });
diff --git a/ports/rustup.ts b/ports/rustup.ts
index 3ab972e7..0044790b 100644
--- a/ports/rustup.ts
+++ b/ports/rustup.ts
@@ -60,7 +60,7 @@ export class Port extends PortBase {
.sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));
}
- latestStable(args: ListAllArgs): Promise {
+ override latestStable(args: ListAllArgs): Promise {
return defaultLatestStable(this, args);
}
@@ -99,14 +99,14 @@ export class Port extends PortBase {
].map(dwnUrlOut);
}
- async download(args: DownloadArgs) {
+ override async download(args: DownloadArgs) {
const urls = this.downloadUrls(args);
await Promise.all(
urls.map((obj) => downloadFile({ ...args, ...obj, mode: 0o700 })),
);
}
- async install(args: InstallArgs) {
+ override async install(args: InstallArgs) {
const installPath = $.path(args.installPath);
if (await installPath.exists()) {
await installPath.remove({ recursive: true });
diff --git a/ports/temporal_cli.ts b/ports/temporal_cli.ts
index 132f2d6a..d8a7c611 100644
--- a/ports/temporal_cli.ts
+++ b/ports/temporal_cli.ts
@@ -33,7 +33,7 @@ export class Port extends GithubReleasePort {
repoOwner = "temporalio";
repoName = "cli";
- downloadUrls(args: DownloadArgs) {
+ override downloadUrls(args: DownloadArgs) {
const { installVersion, platform } = args;
let arch;
switch (platform.arch) {
@@ -55,7 +55,7 @@ export class Port extends GithubReleasePort {
].map(dwnUrlOut);
}
- async install(args: InstallArgs) {
+ override async install(args: InstallArgs) {
const [{ name: fileName }] = this.downloadUrls(args);
const fileDwnPath = std_path.resolve(args.downloadPath, fileName);
diff --git a/ports/terraform.ts b/ports/terraform.ts
index f811d5a2..4c88bf75 100644
--- a/ports/terraform.ts
+++ b/ports/terraform.ts
@@ -41,7 +41,7 @@ export class Port extends PortBase {
return versions.reverse();
}
- async latestStable() {
+ override async latestStable() {
const all = await this.listAll();
// stable versions don't have any additional info in theform of 1.2.3-alpha
return all.findLast((str) => !str.match(/-/))!;
@@ -68,14 +68,14 @@ export class Port extends PortBase {
].map(dwnUrlOut);
}
- async download(args: DownloadArgs) {
+ override async download(args: DownloadArgs) {
const urls = this.downloadUrls(args);
await Promise.all(
urls.map((obj) => downloadFile({ ...args, ...obj })),
);
}
- async install(args: InstallArgs) {
+ override async install(args: InstallArgs) {
const [{ name: fileName }] = this.downloadUrls(args);
const fileDwnPath = std_path.resolve(args.downloadPath, fileName);
diff --git a/ports/wasmedge.ts b/ports/wasmedge.ts
index be3f915b..b35175ec 100644
--- a/ports/wasmedge.ts
+++ b/ports/wasmedge.ts
@@ -63,7 +63,7 @@ export class Port extends GithubReleasePort {
repoOwner = "WasmEdge";
repoName = "WasmEdge";
- execEnv(args: ExecEnvArgs) {
+ override execEnv(args: ExecEnvArgs) {
return {
WASMEDGE_DIR: args.installPath,
// WASMEDGE_LIB_DIR: std_path.resolve(args.installPath, "lib64"),
@@ -71,11 +71,11 @@ export class Port extends GithubReleasePort {
};
}
- listLibPaths(): string[] {
+ override listLibPaths(): string[] {
return ["lib*/*"];
}
- downloadUrls(args: DownloadArgs) {
+ override downloadUrls(args: DownloadArgs) {
const { installVersion, platform } = args;
let fileName;
if (platform.os == "darwin") {
@@ -120,7 +120,7 @@ export class Port extends GithubReleasePort {
].map(dwnUrlOut);
}
- async install(args: InstallArgs) {
+ override async install(args: InstallArgs) {
const [{ name: fileName }] = this.downloadUrls(args);
const fileDwnPath = std_path.resolve(args.downloadPath, fileName);
diff --git a/std/sedLock.ts b/std/sedLock.ts
index 9219b807..ccbb2f12 100644
--- a/std/sedLock.ts
+++ b/std/sedLock.ts
@@ -40,6 +40,8 @@ export async function sedLock(
let dirty = false;
+ const workSet = [] as [Path, string][];
+
await $.co(
Object
.entries(lines)
@@ -88,8 +90,7 @@ export async function sedLock(
const newText = rewrite.join("\n");
if (text != newText) {
- await path.writeText(newText);
- $.logStep(`Updated ${workingDir.relative(path)}`);
+ workSet.push([path, newText]);
dirty = true;
} else {
// $.logLight(`No change ${workingDir.relative(path)}`);
@@ -107,5 +108,13 @@ export async function sedLock(
}),
);
+ // we prefer all settled for the destructive operation
+ await Promise.allSettled(
+ workSet.map(async ([path, newText]) => {
+ await path.writeText(newText);
+ $.logStep(`Updated ${workingDir.relative(path)}`);
+ }),
+ );
+
return dirty;
}
diff --git a/tests/envs.ts b/tests/envs.ts
index 7318226a..f18a6937 100644
--- a/tests/envs.ts
+++ b/tests/envs.ts
@@ -48,9 +48,14 @@ const envVarTestEnvs: EnvDefArgs[] = [
const envVarTestsPosix = `
set -ex
# by default, we should be in main
-[ "$SONG" = "ditto" ] || exit 101
+[ "$SONG" = "ditto" ] || exit 1010
[ "$GHJK_ENV" = "main" ] || exit 1011
+# vars should be gone after deactivation
+ghjk_deactivate
+[ "$SONG" = "ditto" ] && exit 1022
+[ "$GHJK_ENV" = "main" ] && exit 1022
+
ghjk envs cook sss
. .ghjk/envs/sss/activate.sh
# by default, envs should be based on main
@@ -60,6 +65,7 @@ ghjk envs cook sss
[ "$GHJK_ENV" = "sss" ] || exit 1012
# go back to main and "sss" variables shouldn't be around
+# through deactivation
. .ghjk/envs/main/activate.sh
[ "$SONG" = "ditto" ] || exit 104
[ "$SING" = "Seoul Sonyo Sound" ] && exit 105
@@ -78,6 +84,11 @@ set fish_trace 1
test "$SONG" = "ditto"; or exit 101;
test "$GHJK_ENV" = "main"; or exit 1010;
+# vars should be gone after deactivation
+ghjk_deactivate
+test "$SONG" = "ditto"; and exit 101;
+test "$GHJK_ENV" = "main"; and exit 1010;
+
ghjk envs cook sss
. .ghjk/envs/sss/activate.fish
# by default, envs should be based on main
diff --git a/tests/ports.ts b/tests/ports.ts
index 9559bdf4..d659aab8 100644
--- a/tests/ports.ts
+++ b/tests/ports.ts
@@ -11,6 +11,9 @@ type CustomE2eTestCase = Omit & {
installConf: InstallConfigFat | InstallConfigFat[];
secureConf?: FileArgs;
};
+
+// FIXME: where did the asdf test go?
+
// order tests by download size to make failed runs less expensive
const cases: CustomE2eTestCase[] = [
// 0 megs
@@ -187,6 +190,9 @@ const cases: CustomE2eTestCase[] = [
profile: "minimal",
},
}),
+ secureConf: {
+ enableRuntimes: true,
+ },
ePoint: `sd --version`,
},
// rust + cargo_binstall + 22 megs
@@ -199,6 +205,9 @@ const cases: CustomE2eTestCase[] = [
profile: "minimal",
},
}),
+ secureConf: {
+ enableRuntimes: true,
+ },
ePoint: `sd --version`,
},
];
diff --git a/tests/reloadHooks.ts b/tests/reloadHooks.ts
index 8f03679a..d190dc99 100644
--- a/tests/reloadHooks.ts
+++ b/tests/reloadHooks.ts
@@ -38,6 +38,10 @@ echo "test" > $GHJK_NEXTFILE
const posixNonInteractiveScript = `
set -eux
+# FIXME: make decision about this
+# test that ghjk_reload doesn't run by default on non-interactive shells
+# [ "\${DUMMY_ENV:-}" = "dummy" ] && exit 1011
+
# test that ghjk_reload is avail because BASH_ENV exposed by the suite
ghjk_reload
[ "\${DUMMY_ENV:-}" = "dummy" ] || exit 101
@@ -103,6 +107,9 @@ test $DUMMY_ENV = "dummy"; or exit 105
const fishNoninteractiveScript = `
set fish_trace 1
+# test that ghjk_reload doesn't run by default on non-interactive shells
+# test $DUMMY_ENV = "dummy"; and exit 1011
+
# test that ghjk_reload is avail because config.fish exposed by the suite
ghjk_reload
diff --git a/utils/mod.ts b/utils/mod.ts
index 8dfb4c0a..04688421 100644
--- a/utils/mod.ts
+++ b/utils/mod.ts
@@ -290,7 +290,7 @@ export function inWorker() {
self instanceof WorkerGlobalScope;
}
-export async function findEntryRecursive(path: string, name: string) {
+export async function findEntryRecursive(path: string | Path, name: string) {
let current = $.path(path);
while (true) {
const location = `${current}/${name}`;