A fresh approach to managing common development tasks like running tests, checking code quality, or building documentation.
Mold is heavily built around a few core ideas:
By reusing parameterized modules, Mold enables new projects to rapidly get off the ground with a set of standard tasks. For example, python.mold provides tasks for general Python project maintenance: autoformatting with black, linting with flake8, documentation generation with Sphinx, etc.
These modules can also provide consistency across projects from
different teams, platforms, and toolchains: linting can generally be run with the
lint
recipe, tests can generally be run with the test
recipe, etc. Consistency cuts down on time spent onboarding and adjusting after
switching projects
When consistency between projects can't be achieved completely, Mold makes your
tasks discoverable and accessible without having
to dig up the documentation. Simply running mold
will list all of the
magic spells in your project's grimoire.
Check the GitHub releases page for binaries, or get the ready-to-use shell script here:
curl -sSfL xtfc.org/mold.sh | sh
mold.sh is a stand-in for the
Mold binary. It's intended to be tracked by version control, so
it's suitable for use in environments that don't already have Mold installed,
like CI/CD or your coworker's computer. It does require the host environment to
have internet access and wget
or curl
installed, as it transparently downloads a full binary to handle actual
execution.
Mold is so fun and easy to use. Just type mold
(or
maybe ./mold.sh
, if you're doing it that way). It should present
you with a list of tasks and helpful descriptions. If you append a task name to
the command, like mold foo
, it will execute the
foo
task for you. You can run many tasks in sequence, like
mold foo bar
.
There's also some other junk sitting around if you run mold --help
.
Mold reads a recipe file that describes the available incantations and all sorts of fun parameterization options. Recipe files are written in YAML. Maybe some day it will support XCL.
A recipe file describes tasks that can be executed, script runtimes, environment variable definitions, and conditional environment configurations. It may also define a required minimum version of Mold.
A recipe describes a task that can be executed and can take any of several forms:
A command is an executable and a list of arguments. It does not support any sort of variable substitution or interpolation; the list of arguments is used as a literal and passed straight to the OS for execution.
A script is an inline script file and a script runtime. The inline script will be written to a temporary file and invoked using the script runtime. This is suitable for small scripts on the order of ~10 lines.
A file is a separate script file, located in the
mold/
directory by default, and a script runtime. The file will
be invoked using the script runtime. This is suitable for scripts of any size
or language. The script file directory can be changed in the root of the
recipe file.
A module is a reference to a remote Git repository that contains a separate Mold configuration. Modules can target a specific branch / tag as well as a specific recipe file inside the repo. Recipes inside the module can be accessed with a prefix.
All recipes can be configured with an optional help string, prerequisite tasks, environment variable definitions, and conditional environment variable definitions.
A runtime defines an interpreter that can be used to execute
scripts and files. Runtimes are defined by a name, command, and file
extensions. The name is used as an identifier by scripts and files, so it must
be unique. The command is a list of arguments that can be passed to the OS to
execute the interpreter; any "?"
elements will be replaced with
the file to be executed. The file extensions are defined as a list of
potential extensions to attach to a filename.
See std.mold for example runtime definitions.
An include is a reference to a module that is included at the top-level, rather than behind a namespace prefix. This is useful for things like std.mold that define general-purpose runtimes or recipes.
Environment variables are used to parameterize recipes. When using modules, it's often beneficial to use variables to ensure the module is generalized sufficiently. Variables can be configured at the root level or at an individual recipe level.
Mold automatically exports several environment variables that describe its runtime context:
$MOLD_ROOT
: directory containing the recipe file$MOLD_FILE
: recipe file path$MOLD_DIR
: recipe directory path$MOLD_CLONE_DIR
: directory containing module repositories$MOLD_SCRIPT_DIR
: directory containing temporary script files$MOLD_SEARCH_DIR
: directory searched for recipe files$MOLD_WORK_DIR
: working directory$MOLD_MODULE_ROOT
: directory containing recipe file for current recipe's moduleIn simple configurations, several of the directories will be identical, but they can be useful in more complicated configurations involving nested modules.
Conditional environments allow environment variables to be defined based on a runtime setting. Environments are defined as a test expression and a variable map. The test is a simple expression that checks for the presence or absence of values in the active Mold environment list. If a test evaluates to true, the corresponding variable map will be applied. Conditional environments are applied in-order, overwriting values defined in the non-conditional variables map and in previous conditional environments.
Active environments are set as a comma-separated list of
alphanumeric strings in the $MOLDENV
environment variable or the --env
/ -e
CLI flag.
Additional environments can be appended one at a time using the
--add
/ -a
CLI flag.
Test expressions are written in a minimal language designed
for checking combinations of active environments. Any environment identifier
evaluates to true
if that identifier is active. Boolean
and
is expressed with the +
operator, while boolean
or
and not
are expressed with the |
and
~
operators, respectively. Subexpressions can be grouped using
()
.
Environment identifiers can also have underscores and hyphens. Whatever.