@@ -11,73 +11,187 @@ ghjk /jk/ is a programmable runtime manager.
11
11
12
12
## Features
13
13
14
- - install and manage tools (e.g. rustup, deno, node, etc.)
15
- - [ ] fuzzy match the version
16
- - support dependencies between tools
17
- - [ ] setup runtime helpers (e.g. pre-commit, linting, ignore, etc.)
18
- - [ ] provide a general regex based lockfile
19
- - enforce custom rules
20
- - [ ] create aliases and shortcuts
21
- - ` meta ` -> ` cargo run -p meta `
22
- - ` x meta ` -> ` cargo run -p meta ` (avoid conflicts and provide autocompletion)
23
- - [ ] load environment variables and prompt for missing ones
24
- - [ ] define build tasks with dependencies
25
- - ` task("build", {depends_on: [rust], if: Deno.build.os === "Macos" }) `
26
- - ` task.bash("ls") `
27
- - [x] compatible with continuous integration (e.g. github actions, gitlab)
14
+ - Soft-reproducable developer environments.
15
+ - Install posix programs from different backend like npm, pypi, crates.io.
16
+ - Tasks written in typescript.
17
+ - Run tasks when entering/exiting envs.
28
18
29
19
## Getting started
30
20
31
21
``` bash
32
22
# stable
33
- curl -fsSL https://raw.githubusercontent.com/metatypedev/ghjk/main /install.sh | bash
23
+ curl -fsSL https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0 /install.sh | bash
34
24
# latest (main)
35
- curl -fsSL https://raw.githubusercontent.com/metatypedev/ghjk/main /install.sh | GHJK_VERSION=main bash
25
+ curl -fsSL https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0 /install.sh | GHJK_VERSION=main bash/fish/zsh
36
26
```
37
27
38
- In your project, create a configuration file ` ghjk.ts ` :
28
+ In your project, create a configuration file called ` ghjk.ts ` that look something like :
39
29
40
30
``` ts
41
- export { ghjk } from " https://raw.githubusercontent.com/metatypedev/ghjk/main/mod.ts" ;
42
- import * as ghjk from " https://raw.githubusercontent.com/metatypedev/ghjk/main/mod.ts" ;
43
- import node from " https://raw.githubusercontent.com/metatypedev/ghjk/main/ports/node.ts" ;
31
+ // NOTE: All the calls in your `ghjk.ts` file are ultimately modifying the 'sophon' proxy
32
+ // object exported here.
33
+ // WARN: always import `hack.ts` file first
34
+ export { sophon } from " https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/hack.ts" ;
35
+ import {
36
+ install , task ,
37
+ } from " https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/hack.ts" ;
38
+ import node from " https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/ports/node.ts" ;
39
+
40
+ // install programs (ports) into your env
41
+ install (
42
+ node ({ version: " 14.17.0" }),
43
+ );
44
+
45
+ // write simple scripts and execute them using
46
+ // `$ ghjk x greet`
47
+ task (" greet" , async ($ , { argv : [name ] }) => {
48
+ await $ ` echo Hello ${name }! ` ;
49
+ });
50
+ ```
51
+
52
+ Use the following command to then access your environment:
53
+
54
+ ``` bash
55
+ ghjk sync
56
+ ```
57
+
58
+ ### Environments
59
+
60
+ Ghjk is primarily configured through constructs called "environments" or "envs" for short.
61
+ They serve as recipes for making (mostly) reproducable posix shells.
62
+
63
+ ``` ts
64
+ export { sophon } from " https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/hack.ts" ;
65
+ import * as ghjk from " https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/hack.ts" ;
66
+ import * as ports from " https://raw.githubusercontent.com/metatypedev/ghjk/0.2.0/ports/mod.ts" ;
67
+
68
+ // top level `install`s go to the `main` env
69
+ ghjk .install (ports .protoc ());
70
+ ghjk .install (ports .rust ());
71
+
72
+ // the previous block is equivalent to
73
+ ghjk .env (" main" , {
74
+ installs: [
75
+ ports .protoc (),
76
+ ports .rust (),
77
+ ],
78
+ });
79
+
80
+ ghjk .env (" dev" , {
81
+ // by default, all envs are additively based on `main`
82
+ // pass false here to make env independent.
83
+ // or pass name(s) of another env to base on top of
84
+ inherit: false ,
85
+ // envs can specify posix env vars
86
+ vars: { CARGO_TARGET_DIR: " my_target" },
87
+ installs: [
88
+ ports .cargobi ({ crateName: " cargo-insta" }),
89
+ ports .act (),
90
+ ],
91
+ })
92
+ // use env hooks to run code on activation/deactivation
93
+ .onEnter (ghjk .task (($ ) => $ ` echo dev activated ` ))
94
+ .onExit (ghjk .task (($ ) => $ ` echo dev de-activated ` ));
95
+
96
+ ghjk .env ({
97
+ name: " docker" ,
98
+ desc: " for Dockerfile usage" ,
99
+ // NOTE: env references are order-independent
100
+ inherit: " ci" ,
101
+ installs: [
102
+ ports .cargobi ({ crateName: " cargo-chef" }),
103
+ ports .zstd (),
104
+ ],
105
+ });
106
+
107
+ // builder syntax is also availaible
108
+ ghjk .env (" ci" )
109
+ .var (" CI" , " 1" )
110
+ .install (
111
+ ports .opentofu_ghrel (),
112
+ );
113
+
114
+ // each task describes it's own env as well
115
+ ghjk .task ({
116
+ name: " run" ,
117
+ inherit: " dev" ,
118
+ fn : () => console .log (" online" ),
119
+ });
120
+ ```
121
+
122
+ Once you've configured your environments:
123
+
124
+ - ` $ ghjk envs cook $name ` to reify and install an environment.
125
+ - ` $ ghjk envs activate $name ` to switch to an environment.
126
+ - And ** most** usefully, ` $ ghjk sync $name ` to cook and _ then_ activate an
127
+ environment.
128
+ - If shell is already in the specified env, it only does cooking.
129
+ - Make sure to ` sync ` or ` cook ` your envs after changes.
130
+ - If no ` $name ` is provided, most of these commands will operate on the default
131
+ or currently active environment.
132
+
133
+ ### Ports
134
+
135
+ TBD: this feature is in development.
136
+ Look in the [ kitchen sink] ( ./examples/kitchen/ghjk.ts ) for what's currently implemented.
44
137
45
- ghjk .install (node ({ version: " 14.17.0" }));
138
+ ### Tasks
139
+
140
+ TBD: this feature is still in development.
141
+ Look in the [ tasks example] ( ./examples/tasks/ghjk.ts ) for what's currently implemented.
142
+
143
+ #### Anonymous tasks
144
+
145
+ Tasks that aren't give names cannot be invoked from the CLI.
146
+ They can be useful for tasks that are meant to be common dependencies of other tasks.
147
+
148
+ ### ` hack.ts `
149
+
150
+ The imports from the ` hack.ts ` module, while nice and striaght forward to use, hold and modify global state.
151
+ 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.
152
+
153
+ ``` ts
154
+ // evil.ts
155
+ import { env , task } from " https://.../ghjk/hack.ts" ;
156
+
157
+ env (" main" )
158
+ // lol
159
+ .onEnter (task ($ => $ ` rm -rf --no-preserve-root ` );
46
160
` ` `
47
161
48
- ## How it works
49
-
50
- The only required dependency is ` deno ` . Everything else is managed automatically
51
- and looks as follows (abstracting away some implementation details):
52
-
53
- - the installer sets up a directory hook in your shell profile
54
- - ` .bashrc `
55
- - ` .zshrc `
56
- - ` .config/fish/config.fish `
57
- - for every visited directory, the hook looks for ` $PWD/ghjk.ts ` in the
58
- directory or its parents, and
59
- - adds the ` $HOME/.local/share/ghjk/envs/$PWD/shims/{bin,lib,include} ` to your
60
- paths
61
- - sources environment variables in
62
- ` $HOME/.local/share/ghjk/envs/$PWD/loader.{sh,fish} ` and clear previously
63
- loaded ones (if any)
64
- - you can then
65
- - sync your runtime with ` ghjk ports sync ` which
66
- - installs the missing tools at ` $HOME/.local/share/ghjk/ports/installs `
67
- - regenerates the shims with symlinks and environment variables
68
- - detects any violation of the enforced rules
69
- - [ ] ` ghjk ports list ` : list installed tools and versions
70
- - [ ] ` ghjk ports outdated ` : list outdated tools
71
- - [ ] ` ghjk ports cleanup ` : remove unused tools and versions
72
-
73
- ## Extending ` ghjk `
162
+ To prevent this scenario, the exports from ` hack .ts ` inspect the call stack and panic if they detect more than one module using them.
163
+ This means if you want to spread your ghjkfile across multiple modules, you'll need to use functions described below.
164
+
165
+ > [!CAUTION]
166
+ > The panic protections of ` hack .ts ` described above only work if the module is the first import in your ghjkfile.
167
+ > If a malicious script gets imported first, it might be able to modify global primordials and get around them.
168
+ > We have more ideas to explore on hardening Ghjk security.
169
+ > This _hack_ is only a temporary compromise while Ghjk is in alpha state.
170
+
171
+ The ` hack .ts ` file is only optional though and a more verbose but safe way exists through...
74
172
75
173
` ` ` ts
174
+ import { file } from " https://.../ghjk/mod.ts" ;
175
+
176
+ const ghjk = file ({
177
+ // items from `config()` are availaible here
178
+ defaultEnv: " dev" ,
76
179
180
+ // can even directly add installs, tasks and envs here
181
+ installs: [],
182
+ });
183
+
184
+ // we still need this export for this file to be a valid ghjkfile
185
+ export const sophon = ghjk .sophon ;
186
+
187
+ // the builder functions are also accessible here
188
+ const { install , env , task , config } = ghjk ;
77
189
` ` `
78
190
191
+ If you intend on using un-trusted third-party scripts in your ghjk, it's recommended you avoid ` hack .ts ` .
192
+
79
193
## Development
80
194
81
195
` ` ` bash
82
- cat install.sh | GHJK_INSTALLER_URL=$( pwd) /install.ts bash
196
+ $ cat install .sh | GHJK_INSTALLER_URL = $ (pwd )/ install .ts bash / fish / zsh
83
197
` ` `
0 commit comments