This is a very early prototype. Please disregard.
... unless you're really really really interested, and maybe wanna contribute. Then feel free to read on.
wfx
(it stands for either "Warpforge Extensions" or "Warpforge Effects" (mentally pronounce "fx" as "effects"))...
... is a "Make-like" tool, which is configured in a Starlark dialect.
Use it to:
- invoke commands, and
- efficiently maintain a filesystem that contains generated content that should be kept up-to-date.
- Declarative configuration file.
- Feels a bit like
make
: you write targets; you say what actions to take to produce and maintain each target; likemake
,wfx
will parse this declaration file, and make those targets easy to run. - Write Starlark (it's a python dialect). Any function with a param named "fx" is a ==target== for
wfx
. (E.g.def install(fx):
meanswfx install
is gonna do whatever you say next.)
- Feels a bit like
- Declare dependencies: Execution is a DAG -- evaluating a target causes its dependencies to be evaluated first; and all targets are evaluated exactly once, no matter how many times they might be depended on.
- tl;dr: this is probably what you want -- it's the kind of behavior
make
gives you, too.
- tl;dr: this is probably what you want -- it's the kind of behavior
- Self-analyzing: run
wfx --listtargets
to get a list of all the possible actions you can take with the current config file. - FUTURE: Run anything.
cmd("foo --bar && baz | frob")
invokes a shell, and executes thefoo
,baz
, andfrob
processes within it. - FUTURE: Customize anything.
cmd = cmd.customize(shell="/bin/fish")
, if you want to use the Fish shell instead of the default Bash, for example. - FUTURE: Easily fetch data, so that bootstrapping other systems is easy. Downloading (both from URLs, and from content-addressed sources!) is natively supported. (No more worrying about whether
wget
orcurl
is installed!) - FUTURE: Keep things up-to-date easily: targets can "own" some output filesystem paths, and can be trusted to keep them updated in the most efficient way possible (e.g., updating them when appropriate, while also no-op'ing fast whenever possible).
- Combined with the dependency DAG: each target having the ability to decide that it's already satisfactorily up-to-date means that whole graphs of dependencies can be very fast to (partially!) evaluate when repeated.
- FUTURE: Easily invoke
warpforge
-- use this anytime you have a task you want done in a sandbox, rather than having host effects! (Or, if you just want the content-addressed memoization superpower!)
This is the smallest possible make.fx
file:
def hello(fx):
cmd("echo hello!")
You can run that as wfx hello
, and it'll... do what you expect. :)
A make.fx
file containing multiple targets, which depend on each other, looks like this:
def task_a(fx, depends_on=['task_b', 'task_c']):
pass
def task_b(fx, depends_on=['task_c']):
pass
def task_c(fx):
pass
In that example, runing wfx task_a
will run all three tasks; running wfx task_b
will only run two.
You can declare that a target "owns" some files, and so should be invoked only when they're out of date:
def owns_a_file(fx_files=['foo.a']):
pass
(Note: not all features shown here are fully implemented (yet). The examples are for syntax only.)
- Be a useful tool. Help people get shit done.
wfx
is aiming for productivity and pragmatism.
- Be legible.
- Even an unfamiliar person should be able to look at a
make.fx
file and say "oh. Yes, I get it" and find the targets by eyeball, with minimal explanation.
- Even an unfamiliar person should be able to look at a
- Be easy to author.
- Writing the minimal hello-world
make.fx
file should be so few keystrokes that you can bang one out from memory in 3 seconds or less.
- Writing the minimal hello-world
- Be predictable. Be deterministic.
- Absolutely no randomization behaviors allowed.
- Be powerful. Be a gateway.
- Lots of other tools do lots of powerful things.
wfx
should be good at invoking them to do what they do best (and not necessarily try to gain every feature itself!). - Looking at a
make.fx
file should be a good way to rapidly discover what actions can be taken on a filesystem, even (or especially) if you don't have existing familiarity with the other tools being invoked.
- Lots of other tools do lots of powerful things.
And also:
- Play nice with computation-addressable and content-addressable friends!
wfx
is a tool for having effects on a filesystem, where the user controls the naming: e.g.,wfx
wants to let the user say "put the foobar tool in the path '/stuff/apps/foobar', then run it".- By contrast,
warpforge
is a tool for running things inside a container (no effects on the host), and works almost exclusively with content-addressed storage (meaning it doesn't accept user instructions about placing things in named paths). - ... This is a match made in heaven!
wfx
can be used to invokewarpforge
, take the outputs ofwarpforge
's work, and then declare where they should be unpacked on the host, and what happens next!
Compared to Make:
- similar: it's declarative, and has a DAG of targets.
- similar: you invoke it with target names --
make install
andwfx install
would both cause the respective tools to look for a target named "install", evaluate all its dependencies, and then evaluate that target. - different:
wfx
uses Starlark syntax (aka, a Pythonic syntax). - different:
wfx
has "phony" targets by default; it only has filesystem related targets if you explicitly say so. (Removes many strange "bugs" that may occur if you try to usemake
in the ways most humans in post-year-2000 usually use it...)
The Starlark syntax has a lot of implications. We think these are all significant improvements over Makefile syntax:
- No escaping hell! Starlark syntax is what you'd expect from anything post-year-2000. Strings are quoted. Function calls look like function calls. There's not a lot of surprises and not a lot of weirdness.
- You can use regular functions for composition! No wild and crazy macros needed; functions get the job done.
- Sheer familiarity. Even if you don't use Python, the syntax is rapid to learn and grok.
- Fewer gotchas. In general, if you write something totally malformed in Starlark, it's a syntax error. In make syntax, it's often unclear if you've escaped something correctly, or not... and it might not break... right away... even if it will, someday.
You can see more examples in the fixtures directory!
All of the fixtures in that directory are working examples (and not merely documentation, but are part of our automated regression tests). You can copy them directly, and be sure they'll operate as shown.
wfx
is implemented in Golang.
The commands to build and test and generally wrangle the codebase are the usual: go test ./...
, etc.
The CLI tool is produced by running go install ./cmd/...
(and typically this will emit the result in ~/go/bin/
, unless you've set up something different).
We also use the go-serum-analyzer tool, which performs static analysis on our error handling to make sure it's both well-documented and correctly-handled.
Tests are mostly stored in markdown files, in the testmark format. (This way, they serve as both living documentation, and as tests!)
If you'd like to contribute to wfx
, please make sure:
- Discussion and documentation should be included with any proposed change or additions!
- The tests should still pass.
- Any new features should include new tests for the feature!
- The error analyser should also still give a passing grade.
- Code should be correctly formatted, etc (e.g.
go fmt
).
wfx
is open source for you to use and share. We hope it's helpful!
SPDX-License-Identifier: Apache-2.0 OR MIT