@@ -38,69 +38,103 @@ import * as tea from "https://raw.github.com/teaxyz/lib/v0/mod.ts"
3838
3939## Usage
4040
41- To install and utilize Python 3.10:
41+ ``` ts
42+ import { porcelain } from " @teaxyz/lib" ;
43+ const { run } = porcelain ;
44+
45+ await run (` python -c 'print("Hello, World!")' ` ).exec ();
46+ // ^^ installs python and its deps (into ~/.tea/python.org/v3.x.y)
47+ // ^^ runs the command
48+ // ^^ output goes to the terminal
49+ // ^^ throws on execution error or non-zero exit code
50+ // ^^ executes via `/bin/sh` (so quoting and that work as expected)
51+ ```
52+
53+ Capturing stdout is easy:
4254
4355``` ts
44- import { prefab , semver , hooks } from " @teaxyz/lib"
45- import { exec } from " node:child_process"
46- const { install, hydrate, resolve } = prefab
47- const { useSync, useShellEnv } = hooks
48-
49- // ensure pantry exists and is up-to-date
50- await useSync ()
51-
52- // define the pkg(s) you want
53- // see https://devhints.io/semver for semver syntax (~, ^, etc)
54- const pkg = { project: ' python.org' , constraint: semver .Range (" ~3.10" ) }
55- // hydrate the full dependency tree
56- const { pkgs : tree } = await hydrate (pkg )
57- // resolve the tree of constraints to specific package versions
58- const { installed, pending } = await resolve (tree )
59-
60- for (const pkg of pending ) {
61- const installation = await install (pkg )
62- // ^^ install packages that aren’t yet installed
63- // ^^ takes a logger parameter so you can show progress to the user
64- // ^^ you could do these in parallel to speed things up
65- // ^^ by default, versioned installs go to ~/.tea, separated from the user’s system. The install location can be customized, see next section.
66- await link (installation )
67- // ^^ creates v*, vx, vx.y symlinks ∵ some packages depend on this
68- installed .push (installation )
69- }
70-
71- const { map, flatten } = useShellEnv ()
72- const env = flatten (map (installed ))
73-
74- exec (" python -c 'print(\" Hello, World!\" )'" , { env })
75-
76- // the above is quite verbose, but we’ll provide a façade pattern soon
56+ const { stdout } = await run (` ruby -e 'puts ", World!"' ` , { stdout: true });
57+ console .log (" Hello," , code );
7758```
7859
60+ > ` { stderr: true } ` also works.
61+
62+ If there’s a non-zero exit code, we ` throw ` . However, when you need to,
63+ you can capture it instead:
64+
65+ ``` ts
66+ const { status } = await run (` perl -e 'exit(7)' ` , { status: true });
67+ assert (status == 7 ); // ^^ didn’t throw!
68+ ```
69+
70+ > The run function’s options also takes ` env ` if you need to supplement or
71+ > replace the inherited environment (which is passed by default).
72+
73+ Need a specific version of something? [ tea] [ tea/cli ] can install any version
74+ of any package:
75+
76+ ``` ts
77+ const { install, run } = porcelain ;
78+
79+ const node16 = await install (" nodejs.org^16.18" ); // ※ https://devhints.io/semver
80+
81+ await run ([' node' , ' -e' , ' console.log(process.version)' ]);
82+ // => v16.18.1
83+ ```
84+
85+ > Notice we passed args as ` string[] ` . This is also supported and is often
86+ > preferable since shell quoting rules can be tricky. If you pass ` string[] `
87+ > we execute the command directly rather than via ` /bin/sh ` .
88+
7989All of tea’s packages are relocatable so you can configure libtea to install
8090wherever you want:
8191
8292``` ts
83- import { hooks , Path } from " tea"
84- const { useConfig } = hooks
93+ import { hooks , Path , porcelain } from " tea" ;
94+ const { install } = porcelain ;
95+ const { useConfig } = hooks ;
8596
86- useConfig ({ prefix: Path .home ().join (" .local/share/my-app" ) })
87- // ^^ must be done before any other libtea calls
97+ useConfig ({ prefix: Path .home ().join (" .local/share/my-app" ) });
98+ // ^^ must be done ** before** any other libtea calls
8899
89- // now if you install python you’ll get:
90- // /home/you/.local/share/my-app/python.org/v3.10.11/bin/python
100+ const go = await install ( " go.dev " );
101+ // ^^ /home/you/.local/share/my-app/go.dev/v1.20.4
91102```
92103
93- ### Notes
104+ ### Designed for Composibility
94105
95- We use a hook-like pattern because it is great. This library is not itself
96- designed for React.
106+ The library is split into [ plumbing] and [ porcelain] (copying git’s lead).
107+ The porcelain is what most people need, but if you need more control, dive
108+ into the porcelain sources to see how to use the plumbing primitives to get
109+ precisely what you need.
110+
111+ For example if you want to run a command with node’s ` spawn ` instead it is
112+ simple enough to first use our porcelain ` install ` function then grab the
113+ ` env ` you’ll need to pass to ` spawn ` using our ` useShellEnv ` hook.
114+
115+ Perhaps what you create should go into the porcelain? If so, please open a PR.
116+
117+ ### Logging
118+
119+ Most functions take an optional ` logger ` parameter so you can output logging
120+ information if you so choose. ` tea/cli ` has a fairly sophisticated logger, so
121+ go check that out if you want. For our porcelain functions we provide a simple
122+ debug-friendly logger (` ConsoleLogger ` ) that will output everything via
123+ ` console.error ` :
124+
125+ ``` ts
126+ import { porcelain , plumbing , utils } from " tea"
127+ const { ConsoleLogger } = utils
128+ const { run } = porcelain
129+
130+ const logger = ConsoleLogger ()
131+ await run (" youtube-dl youtu.be/xiq5euezOEQ" , logger ).exec ()
132+ ```
97133
98134### Caveats
99135
100- If the user has no existing tea/cli or you use your own prefix then the
101- pantry must be sync’d with ` useSync() ` at least once. ` useSync ` requires
102- either ` git ` or ` tar ` to be in ` PATH ` . We’ll remove this requirement with
103- time.
136+ We use a hook-like pattern because it is great. This library is not itself
137+ designed for React.
104138
105139We have our own implementation of semver because open source has existed for
106140decades and Semantic Versioning is much newer than that. Our implementation is
@@ -114,10 +148,15 @@ before any other calls might happen. We call it explicitly in our code so you
114148will need to call it yourself in such a case. This is not ideal and we’d
115149appreciate your help in fixing it.
116150
117- There is minimal magic, [ tea/cli] has magic because the end-user appreciates
118- it but libraries need well defined behavior. We will provide a façade patterns
119- to make life easier, but the primitives of libtea require you to read the
120- docs to use them effectively.
151+ The plumbing has no magic. Libraries need well defined behavior.
152+ You’ll need to read the docs to use them effectively.
153+
154+ libtea almost certainly will not work in a browser. Potentially its possible.
155+ The first step would be compiling our bottles to WASM. We could use your help
156+ with that…
157+
158+ Windows is not yet supported, but we otherwise support everything tea/cli
159+ does.
121160
122161## What Packages are Available?
123162
@@ -127,6 +166,9 @@ If something you need is not there, adding to the pantry has been designed to
127166be an easy and enjoyable process. Your contribution is both welcome and
128167desired!
129168
169+ To see what is available refer to the [ pantry] docs or you can run:
170+ ` tea pkg search foo ` .
171+
130172  ;
131173
132174
@@ -139,7 +181,12 @@ We would be thrilled to hear your ideas† or receive your pull requests.
139181## Anatomy
140182
141183The code is written with Deno (just like [ tea/cli] ) but is compiled to a
142- node package for wider accessibility (and ∵ [ tea/gui] is node/electron)
184+ node package for wider accessibility (and ∵ [ tea/gui] is node/electron).
185+
186+ The library is architected into hooks, plumbing and porcelain. Where the hooks
187+ represent the low level primitives of pkging, the plumbing glues those
188+ primitives together into useful components and the porcelain is a user
189+ friendly * façade* pattern for the plumbing.
143190
144191## Supporting Other Languages
145192
@@ -149,19 +196,26 @@ the scope *tight*. Probably we would prefer to have one repo per language.
149196tea has sensible rules for how packages are defined and installed so writing
150197a port should be simple.
151198
199+ We would love to explore how possible writing this in rust and then compiling
200+ to WASM for all other languages would be. Can you help?
201+
152202Open a [ discussion] to start.
153203
154204[ discussion ] : https://github.com/orgs/teaxyz/discussions
155205[ tea/cli ] : https://github.com/teaxyz/cli
156206[ tea/gui ] : https://github.com/teaxyz/gui
157207[ Deno ] : https://deno.land
158208[ pantry ] : https://github.com/teaxyz/pantry
209+ [ plumbing ] : ./plumbing/
210+ [ porcelain ] : ./porcelain/
159211
160212  ;
161213
162214
163215# Tasks
164216
217+ Run eg. ` xc coverage ` or ` xc bump patch ` .
218+
165219## Coverage
166220
167221``` sh
@@ -170,3 +224,26 @@ deno coverage cov_profile --lcov --output=cov_profile.lcov
170224tea genhtml -o cov_profile/html cov_profile.lcov
171225open cov_profile/html/index.html
172226```
227+
228+ ## Bump
229+
230+ Bumps version by creating a pre-release which then engages the deployment
231+ infra in GitHub Actions.
232+
233+ ``` sh
234+ if ! git diff-index --quiet HEAD --; then
235+ echo " error: dirty working tree" >&2
236+ exit 1
237+ fi
238+
239+ if [ " $( git rev-parse --abbrev-ref HEAD) " != " main" ]; then
240+ echo " error: requires main branch" >&2
241+ exit 1
242+ fi
243+
244+ V=$( git describe --tags --abbrev=0 --match " v[0-9]*.[0-9]*.[0-9]*" )
245+ V=$( tea semverator bump $V $PRIORITY )
246+
247+ git push origin main
248+ tea gh release create " v$V " --prerelease --generate-notes --title
249+ ```
0 commit comments