Skip to content

Latest commit

 

History

History
901 lines (687 loc) · 24.9 KB

README.md

File metadata and controls

901 lines (687 loc) · 24.9 KB

tea

tea is not a package manager.

tea is unified packaging infrastructure.

From the creator of brew, tea is a standalone, binary download for all platforms that puts the entire open source ecosystem at your fingertips. Casually and effortlessly use the latest and greatest or the oldest and most mature from any layer of any stack. Break down the silos between programming communities, throw together scripts that use entirely separate tools and languages and share them with the world with a simple one-liner.

All you need is tea.

 

tea is pre v1. This means there may still be some niggles in day to day use. It also means that you should absolutely get involved. This is the key and golden time when getting involved is both easy and hugely fun. We look forward to meeting you 👊

 

tea/cli 0.11.14

Open Source is a treasure trove—yet those chests are sealed with gnarly locks. tea is the key:

$ tea +rust-lang.org

tea: installing rust-lang.org and 13 other packages into a temporary sandbox
when done type: exit

tea $ cat <<EOF>hello.rs
fn main() {
  println!("Hello World!");
}
EOF
$ rustc hello.rs -o hello
$ ./hello
Hello World!

tea $ exit

$ rustc
command not found: rustc

tea doesn’t install packages—at least not in a conventional sense—we stow them in ~/.tea†. Your system remains pristine and isolated from tea’s activity. But everything is right there when you need it.

finally a package manager where all the packages are relocatable (like they should be).

tea Pipelines

tea’s +pkg syntax puts the whole open source ecosystem at your fingertips, if you stop at the +pkg then the above happens—we open a new shell with those packages in the environment—but if you keep typing you can construct direct usage:

$ tea +nodejs.org npx --yes browser-sync start --server
# ^^ one-liner to start a local web server with live reload

$ sh <(curl tea.xyz) +nodejs.org npx --yes browser-sync start --server
# ^^ same one-liner but works for anyone on the Internet
# (if tea is already installed, it uses it, if not it *doesn’t* install tea,
#  a temporary sandbox is created)

Compose everything, combine everything, just like the UNIX philosophy envisaged. Of course that also means you can pipe them:

$ tea +gnu.org/wget wget -qO- tea.xyz/white-paper | tea +charm.sh/glow glow -

Notably, with -X syntax this can expressed more simply:

$ tea -X wget -qO- tea.xyz/white-paper | tea -X glow -

Further Examples

It’s 202x so obviously we also can download scripts from the Internet:

$ sh <(curl tea.xyz) +charm.sh/gum https://github.com/charmbracelet/gum/blob/main/examples/demo.sh

Want to try out the latest version of node, but not sure if it will work with your project? tea makes it easy.

$ tea +nodejs.org^19 npm start

One liner to create a react app:

$ sh <(curl tea.xyz) -X npx create-react-app my-app

Coming Soon

tea pipelines are so interesting we intend to have a dedicated showcase for them.

 

tea: the Universal Interpreter

$ tea https://github.com/teaxyz/demos/blob/main/demo.go input.txt
tea: installing go 1.18.3
go: running demo.go
…

In this basic example we know to install go first based on the file extension. Obvious right? Which is why we didn’t stop there:

$ tea favicon-generator.sh input.png
installing image-magick, optipng, guetzli and 3 other dependencies…
…
output: favicon-128.png…

$ cat favicon-generator.sh
#!/usr/bin/env tea
#---
# args: [/bin/sh, -e]
# dependencies:
#     imagemagick.org: 4
#     optipng.sourceforge.net: 1
# [snip]…
#---

tea reads a file’s YAML front-matter, allowing you to roll in the entire open source ecosystem for your scripts, gists and one-liners. While it runs, the script has these dependencies in its environment, but the rest of your system will never know about them.

We also know a little more magic:

$ tea -X node
tea: installing [email protected]
Welcome to Node.js v18.9.1.
Type ".help" for more information.
>

Typically tea uses fully-qualified-names for packages, but we know what tools they provide, so as long as you know what tool you’re looking for we can figure out the rest.

Coming Soon

---
dependencies:
 nodejs.org: 19
 npmjs.com:
   package.json:
     dependencies:
       react: ^18
---

 

tea: the universal virtual‑environment manager

$ deno
zsh: command not found: deno

$ echo $PATH
/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin

$ cd my-project
$ deno
tea: installing deno.land^1.22
deno 1.27.0
> ^D

$ env
PATH=~/.tea/deno.land/v1.27.0/bin:/usr/bin:/bin
SRCROOT=/src/my-project
VERSION=…
…
What is this sourcery?

tea uses a shell hook to insert the precise tooling your project needs into your shell environment. Development is now containerized at the package manager level. No longer do you need to worry about your team being on different versions of foundational tooling nor do you need to worry about system level updates breaking different projects you’re working on.

There are thousands of version managers for the thousands of tools they support. Probably it’s time we stopped that duplicated effort.

Projects can specify precisely what they need and you can install those requirements precisely be it today, tomorrow or in ten years.

In the above example if deno is not yet installed we insert a hook so trying to execute it will install it first.

PSA: Stop using Docker

Docker is great for deployment and cross compilation, but… let’s face it: it sucks for dev.

Docker stifles builders. It constricts you; you’re immalleable; tech marches onwards but your docker container remains immobile. Nobody knows how to use docker. Once that Dockerfile is set up, nobody dares touch it.

And let’s face it, getting your personal dev and debug tools working inside that image is incredibly frustrating. Why limit your potential?

Keep deploying with Docker, but use tea to develop.

Then when you do deploy you may as well install those deps with tea.

Frankly, tea is properly versioned unlike system packagers, so with tea your deployments actually remain more stable.

You need 34 dependencies to compile our white-paper but with tea there’s nothing to think about:

$ git clone https://github.com/teaxyz/white-paper
$ cd white-paper
$ make  #
tea: installing pandoc.org and 33 other dependencies…
…
$ open tea.white-paper.pdf

Our white-paper’s dependencies are written in plain markdown in our README. tea sets up a virtual environment for them simply by stepping into the directory.

† on macOS you may need to do tea -S first since we re-use the system make (we try to detect system installed deps) and thus we cannot intercept the call

Coming Soon

  • we’ll automatically load and unload completions
  • we’ll allow customizations per package for your project

 

Executable Markdown

Markdown has (justifiably) become the standard documentation format of development. How about instead of writing scripts with comments, we write documentation that can be run.

$ tea .  # interprets `# Getting Started`, could also be `tea ./README.md`
tea: npm install
tea: npm start

$ sh <(curl tea.xyz) https://github.com/my/project
tea: cloning…
tea: npm start

$ git clone https://github.com/my/project
$ cd project
$ tea build
tea: executing `# Build`

Using these scripts in CI is easy:

steps:
  - uses: teaxyz/setup@v0
    with:
      target: build

Check out teaxyz/setup for all that you can do with our GitHub Action.

Coming Soon

This is a limited set of first steps exploring the idea of executable markdown. We intend to sensibly build out concepts for making entire documents executable, and we’d like your help with that. Start a discussion about it.

 

Getting Started

tea is a standalone binary so, if you like, you can just download it yourself. For a little more magic†, however, we recommend our installer:

sh <(curl https://tea.xyz)
# • asks you to confirm before it sets tea up in `~/.tea`
# • asks you to confirm before adding one line to your `~/.shellrc`
# • asks you to confirm before making a `/usr/local/bin/tea` symlink

† if you want tea’s virtual environment manager functionality, the installer is the easiest way.

In fact, the tea one-liner abstracts away installation:

$ sh <(curl tea.xyz) https://example.com/script.ts

# works the same as:
$ tea https://example.com/script.ts

# if tea is installed, our one-liner uses the tea installation, if it’s not
# installed then it **doesn’t install tea** or any dependencies, it creates a
# sandbox and runs everything in there

Now in your blog posts, tweets and tutorials you don’t have to start with any “how to install tea” preamble nor will they need to google anything. If they want to learn about tea first they can go to the same URL as they’re curl’ing. We already work on Linux, macOS, and WSL; soon we’ll support Windows natively.

As a bonus, the installer also updates tea.

Now see here fella’, I hate installers…

We get it! We hate installers. That’s why we package everything! If you don’t want it, then we fully support you in that. Download our latest release and run it from wherever you like.

Installing Manually

tea is a single binary that you can [install yourself][releases].

Now tea’s installed you can omit any instance of sh <(curl tea.xyz) and instead use your locally installed copy of tea.

Our (optional) magic PATH restructuring requires a hook in your ~/.zshrc:

add-zsh-hook -Uz chpwd(){ source <(tea -Eds) }

If this sourcery seems a bit much, you can just use tea as an interpreter instead. eg. tea npm start will execute the correct npm for your environment.

Uninstalling tea
  • You can delete everything under ~/.tea
  • There’s also a one-liner added to your ~/.zshrc you should remove.
  • Finally delete /usr/local/bin/tea

 

Usage as an Environment Manager

You’re a developer, installing tools globally makes no sense. With tea the tools you need per project or script are available to that workspace as virtual environments. Our magic works from depths of libc to the heights of the latests fads in CSS precompilers. All versions†. All platforms‡.

† We’re new software, give us time to achieve this promise.
‡ Windows (native, we support WSL), Raspberry Pi, BeOS, etc. coming soon!

When you cd into a project in your terminal, tea sets up the environment so your tools “just work”. To do this it looks for a dependencies table in your README.

Using the README may seem weird, but really it's the right place to document your dependencies. Typically in open source this information is barely documented, incorrectly documented or duplicated (incorrectly) in various hard to find places. No longer.

Additionally this makes use of tea optional. Your team or your users can source your dependencies themselves if they want. It says right there in a human readable form in the README what they need to get.

Umm, I hate this, can I use a different file?

You can use package.json instead:

{
  "tea": {
    "dependencies": [{ "nodejs.org": 18 }]
  }
}

We check README.md before package.json. You can force use of package.json by disabling magic with --muggle.

For an example see our “dependencies” section (teaception: we use tea to build tea).

You can check what environment this generates with tea:

tea --env --dump

--env specifies that tea will generate an environment based on the source control checkout. So if you’re using git we’ll look around for a .git directory and consider that the SRCROOT for your project. Then we check the README.md there to gather the environment information.

tea attempts to further enhance your environment based on your workspace context:

Variable Description
VERSION Extracted from the README
SRCROOT We descend towards root until we find a source control marker, eg. .git
MANPATH So man … works for your deps

We also provide eg. PKG_CONFIG_PATH, LD_LIBRARY_PATH, DEVELOPER_DIR, etc. so other tools can find your dependencies. We provide other variables for convenience too, like GITHUB_SLUG (extracted from your git remote) which can be surprisingly useful to automation scripts.

These variables are also available to tea Scripts.

 

Usage as an Interpreter

You can use tea to execute pretty much any script from any location. We’ll auto-magically install the right interpreter (as an isolated virtual environment—there are no global consequences to your system).

$ tea my-script.py

tea sees the .py file extension, so it installs the latest version of Python and then executes the script.

If you want more control over the python version then we need to edit the script’s YAML front-matter, eg:

#!/usr/bin/env python

"""
---
dependencies:
  python.org: ^2.7
---
"""

# snip …

tea will run the script with the latest version of Python that is >=2.7 but less than 3.0. If it's not installed we grab it, otherwise we use what is available.

We also support an args parameter which is useful for tools that require a run command like deno or go.

#!/usr/bin/env deno

/*---
dependencies:
  deno.land: ^1.27
args:
  - deno
  - run
  # we put the script filename on the end for you here
---*/

Using a tea Shebang

You can #!/usr/bin/env tea, and you’d possibly choose this because tea can do more than install dependencies. You may recall our earlier diatribe about tools sticking to what they’re good at—we really believe this. Thus having tools evolve to be configurable for project environments is something we think should be left to us.

For example, deno is a wonderful interpreter for JavaScript and TypeScript, but it has no project configuration capabilities which means if you want to use it for scripts you may have to mess around a little. We think deno should stay this way, and instead we can use tea:

#!/usr/bin/env -S tea -E

/* ---
dependencies:
  deno.land: ^1.18
args:
  - deno
  - run
  - --allow-net
  - --import-map={{ srcroot }}/import-map.json
  # ^^ we provide {{srcroot}} which can be enormously useful for scripting
  # note that you must use a `tea -E` shebang for this to work
--- */

// snip …

Which would go like this:

$ pwd
/src
$ ./script.ts my-arg
tea: ~/.tea/deno.land/v1.18/bin/deno run \
  --allow-net \
  --import-map=/src/import-map.json \
  /src/script.ts \
  my-arg

When called with -E tea reads the virtual environment and injects any dependencies from there. Probably your project already specifies your deno dependency, so the above YAML is possibly being redundant.

 

Magic

tea codifies the concept of magic.

In an environment where there is magic we try to be clever and infer what you want. Without magic we are strict and require precise specification of your intent.

You can disable magic by specifying --muggle or exporting MAGIC=0 to your shell environment.

The primary magic we apply is determining if you want to use your virtual environment or not. Strictly tea --env is required to inject it, but when magic is enabled we try to figure out if you just wanted that. Our goal is to be smart and useful for your productivity.

We do some magic per dependency. This is currently hard-coded logic in tea/cli itself, but we intend to make it general with a magic.ts file per package in the pantry.

Currently magic is limited (and a great place for contributions).

For example, if we detect that your project is a GitHub Action we read the action.yml and make the right version of node available.

 

Contributing

If you have suggestions or ideas, start a discussion. If we agree we’ll move it to an issue. Bug fixes straight to pull request or issue please!

Probably the place you’ll want to start is by supplementing the pantry.

Hacking on tea

tea is written in TypeScript using deno.

git clone https://github.com/teaxyz/cli tea
cd tea

tea run foo       # runs the local checkout passing `foo` as an argument
tea install-self  # deploys the local checkout into your `~/.tea`

Things we Need

  • We really need more tests!
  • We need test coverage information
  • More magic for dependencies, eg. knowing what version of node should be in the env based on .node-version files used for other version managers.

Token Rewards

There isn’t a token yet but when it’s brewed it’s quite possible there will be a little something extra for those who helped build tea. 😶‍🌫️

 

FAQ

Where’s tea install?

tea works differently. It’s not “I want to install Freetype” it’s “I want to use Freetype”.

Look, we’re not idiots. We know there are occasions where a good ol’ brew install is what you need. So—for now—continue using brew install. Longer term, we have plans for an extensible commands system.

tea is a set of packaging primitives. We want you to build entirely new things on top of tea. We want to integrate tea into your existing build tools, we eventually want to be the authoritative packaging datastore (isn’t it about time there was one of those?)

Coming soon is tea/cmd. tea/cli will expose forks of this repo as commands the user can run utilizing the power of tea’s packaging primitives to do all that they can imagine. Maybe it’ll be you who writes the tea install command? (If you do, try to do something new, eh? 😌)

May we interest you in a hack?

If you really want to put tea through its paces, you can combine the search magic with your shell’s “command not found” logic, to get automatic tea lookups.

zsh

function command_not_found_handler {
  tea -X $*
}

bash

The following requires bash^4; sadly macOS ships with v3.2, but tea provides +gnu.org/bash, and we’ve met very few people who want to use bash on macs, though I bet you're out there).

function command_not_found_handle {
  tea -X $*
}

fish

function fish_command_not_found
  tea -X $argv
end

How do I find available packages?

We list all packages at tea.xyz. Or open ~/.tea/tea.xyz/var/pantry. We agree this is not great UX.

What are you doing to my computer?

We install compartmentalized packages to ~/.tea.

We then suggest you add our one-liner to your shell .rc and a symlink for /usr/local/bin/tea.

We might not have installed tea, if you used sh <(curl tea.xyz) foo and tea wasn’t already installed, then you we only fetched any packages, including tea, temporarily.

I thought you were decentralized and web3 and shit

tea is creating new technologies that will change how open source is funded. tea/cli is an essential part of that endeavor and is released prior to our protocol in order to bootstrap our holistic vision.

We don’t subscribe to any particular “web” at tea.xyz, our blockchain component will be an implementation detail that you won’t need to think about (but we think you will want to).

Am I or my employer going to have to pay for open source now?

No. Software is a multi-trillion industry. We only have to skim a little off that to pay the entire open source ecosystem. Check out our white-paper for the deets.

Packaging up tea packages with your .app, etc.

Our packages are relocatable by default. Just keep the directory structure the same. And ofc. you are licensed to do so. Honestly we think you should absolutely bundle and deploy tea’s prefix with your software. We designed it so that it would be easier for you to do this than anything that has come before.

I have another question

Start a discussion and we’ll get back to you.

 

 

Appendix

Philosophy

  • Be non‑intrusive

    don’t interfere with our users’ systems or habits

  • Be “just works”

    our users have better things to do than fix us

  • Error messages must be excellent

    trust that if it comes to it, our users can fix things provided we give them a helping hand

  • Be intuitive

    being clever is good—but don’t be so clever nobody gets it

  • Resist complexity

    rethink the problem until a simpler solution emerges

  • Be fast

    we are in the way of our users’ real work, don’t make them wait

Troubleshooting

env: tea: No such file or directory

If you got this error message, you need to install tea: sh <(curl https://tea.xyz).

vs. brew

We don’t aim to replace brew, we see our offerings as somewhat complementary. Still where we have overlapping features:

  • tea doesn’t require you install the Xcode Command Line Tools
  • tea packages are relocatable
  • tea aims to be zippier in all usage
  • tea doesn’t make global changes to your system
  • tea aims to enhance the way you work, rather than impose the way you work
  • tea installs independently for every user on the machine
  • tea is somewhat decentralized and aims to be completely decentralized
  • tea is a tight series of tight, easy-to-understand codebases
  • tea starts building new releases for tools almost immediately
  • tea’s packages are named in a fully-qualified manner
  • tea’s philosophy is user-first and not tea-maintainer-first

 

Tea Scripts

You can execute each of these with tea foo where foo is the name of the section.

Test

FIXME would be nice to be able to specify tests here deno supports --filter but that would require a little massaging.

export TMPDIR=${TMPDIR:-/tmp}

deno test \
 --allow-net \
 --allow-read \
 --allow-env=SRCROOT,GITHUB_TOKEN,TMPDIR,TEA_PREFIX \
 --allow-run \
 --import-map=$SRCROOT/import-map.json \
 --allow-write="$TMPDIR" \
 --unstable \
 "$SRCROOT"/tests/**/*.test.ts

Typecheck

deno check \
  --import-map="$SRCROOT"/import-map.json \
  --unstable \
  src/app.ts \
  "$SRCROOT"/scripts/*.ts

Run

deno run \
  --import-map="$SRCROOT"/import-map.json \
  --unstable \
  --allow-all \
  "$SRCROOT"/src/app.ts

Compile

OUT="$1"
if test -z "$OUT"; then
  OUT="./tea"
else
  shift
fi

deno compile \
  --allow-read \
  --allow-write \
  --allow-net \
  --allow-run \
  --allow-env \
  --unstable \
  --import-map="$SRCROOT/import-map.json" \
  --output "$OUT" \
  "$@" \
  "$SRCROOT/src/app.ts"

Install Self

Installs this working copy into ~/.tea/tea.xyz/vx.y.z.

tea compile "$TEA_PREFIX/tea.xyz/v$VERSION/bin/tea"
"$SRCROOT"/scripts/repair.ts tea.xyz

Dependencies

Project Version
deno.land ^1.27
tea.xyz ^0

macOS >= 11 || linux:glibc >= 23

 

A Brief Diatribe

Every programming language, every build system, every compiler, web server, database and email client seem to gravitate towards adding infinite features and complexity so that their users can do ever more and more.

This is contrary to the UNIX philosophy: tools should do one thing and —by being tight and focused— do it damn well. If they are composable and flexible then they can be combined, piped and leveraged into a larger, more capable toolbox. The Internet is built with this toolbox.

Nowadays every programming language reimplements the same set of libraries and tools because using a well-maintained, mature and portable library that lives higher up the stack adds too much complexity. This extends the adolescence of new languages, results in no single language even becoming truly state of the art and leads to degrees of duplication that make the open source ecosystem fragile. This is to the detriment of all software, everywhere.

tea removes this complexity and adds some much needed robustness for the good of the entire open source ecosystem, the larger Internet and the whole world of software.