The toolchain is an internal layer for downloading, installing, and managing tools (languages, dependency managers, libraries, and binaries) that are required at runtime. We embrace this approach over relying on these tools "existing" in the current environment, as it ensures the following across any environment or machine:
- The version and enabled features of a tool are identical.
- Tools are isolated and unaffected by external sources.
- Builds are consistent, reproducible, and hopefully deterministic.
Furthermore, this avoids a developer, pipeline, machine, etc, having to pre-install all the necessary tools, and to keep them in sync as time passes.
How it works
The toolchain is built around proto, our stand-alone multi-language version manager. moon
will piggyback of proto's toolchain found at
~/.proto and reuse any tools available, or download
and install them if they're missing.
As mentioned above, tools within the toolchain are managed by version for consistency across
machines. These versions are configured on a per-tool basis in
.moon/toolchain.yml. So what kinds of versions are allowed?
- Full versions - A full version is a semantic version that is fully specified, such as
2.0.0-rc.1. This is the most common way to specify a version, and is preferred to avoid subtle deviations.
- Partial versions - A partial version is a version that is either missing a patch number, minor
number, or both, such as
1. These can also be represented with requirement syntax, such as
~1. If using partials, we suggest having a major and minor number to reduce the deviation of versions across machines.
- Aliases - An alias is a human-readable word that maps to a specific version. For example,
stablemaps to the latest version of a tool, or
canarywhich maps to applicable canary release, or even a completely custom alias like
berry. Aliases are language specific, are not managed by moon, and are not suggested for use since they can change at any time (or even daily!).
This sounds great, but how exactly does this work? For full versions and aliases, it's straight
forward, as the resolved version is used as-is (assuming it's a legitimate version), and can be
For partial versions, we first check locally installed versions for a match, by scanning
~/.proto/tools/<tool>. For example, if the requested version is
1.2 and we have
installed locally, we'll use that version instead of downloading the latest
Otherwise, we'll download the latest version that matches the partial version, and install it
The following tools are currently managed by the toolchain.
- Configured with:
- Installed to: