ghjk /gk/ is a set of tools for managing developer environments and an attempt at a successor for asdf.
ghjk is part of the Metatype ecosystem. Consider checking out how this component integrates with the whole ecosystem and browse the documentation to see more examples.
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 and its ghjkfile for a real world example.
- Install standalone posix programs or those found on different backends and registries
- npm
- pypi
- crates.io
- [TBD] Github releases
- Tasks written in typescript
- Ergonomically powered by
dax
. - Built on Deno, most dependencies are an import away.
- Ergonomically powered by
- Soft-reproducible posix environments.
- Declaratively compose envs for developer shells, CI and tasks.
- Run tasks when entering/exiting envs.
Before anything, make sure the following programs are available on the system.
- git
- tar (preferably GNU tar)
- curl
- unzip
- zstd
Install the ghjk cli using the installer scripts like so:
curl -fsSL https://raw.github.com/metatypedev/ghjk/v0.3.0-rc.1/install.sh | bash
Use the following command to create a starter ghjk.ts
in your project directory:
ghjk init ts
Ghjk is primarily configured through constructs called "environments" or "envs" for short. They serve as recipes for making (mostly) reproducible posix shells.
import { file } from "https://raw.github.com/metatypedev/ghjk/v0.3.0-rc.1/mod.ts";
// ports are small programs that install sowtware to your envs
import * as ports from "https://raw.github.com/metatypedev/ghjk/v0.3.0-rc.1/ports/mod.ts";
const ghjk = file({});
// NOTE: `ghjk.ts` files are expected to export this sophon object
// all the functions on the ghjk object are ultimately modifying the 'sophon' proxy
// object exported here.
export const sophon = ghjk.sophon;
// top level `install`s go to the `main` env
ghjk.install(ports.protoc());
ghjk.install(ports.rust());
// the previous block is equivalent to
ghjk.env("main", {
installs: [ports.protoc(), ports.rust()],
});
ghjk
.env("dev", {
// by default, all envs are additively based on `main`
// pass false here to make env independent.
// or pass name(s) of another env to base on top of
inherit: false,
// envs can specify posix env vars
vars: { CARGO_TARGET_DIR: "my_target" },
installs: [ports.cargobi({ crateName: "cargo-insta" }), ports.act()],
})
// use env hooks to run code on activation/deactivation
.onEnter(ghjk.task(($) => $`echo dev activated`))
.onExit(ghjk.task(($) => $`echo dev de-activated`));
ghjk.env({
name: "docker",
desc: "for Dockerfile usage",
// NOTE: env references are order-independent
inherit: "ci",
installs: [ports.cargobi({ crateName: "cargo-chef" }), ports.zstd()],
});
// 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({
name: "run",
inherit: "dev",
fn: () => console.log("online"),
});
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.
enableRuntimes: true,
});
Once you've configured your environments:
$ 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
orcook
your envs after changes.
- Make sure to
- If no
$name
is provided, most of these commands will operate on the default or currently active environment.
More details can be found in the user manual.
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
.
$ deno task dev bash/fish/zsh
Run the tests in the repository through the deno task:
$ deno task test
# this supports filtering
$ deno task test --filter envHooks