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,wfxwill 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 installis 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
makegives you, too.
- tl;dr: this is probably what you want -- it's the kind of behavior
- Self-analyzing: run
wfx --listtargetsto 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, andfrobprocesses 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
wgetorcurlis 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):
passIn 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.
wfxis aiming for productivity and pragmatism.
- Be legible.
- Even an unfamiliar person should be able to look at a
make.fxfile 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.fxfile 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.
wfxshould be good at invoking them to do what they do best (and not necessarily try to gain every feature itself!). - Looking at a
make.fxfile 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!
wfxis a tool for having effects on a filesystem, where the user controls the naming: e.g.,wfxwants to let the user say "put the foobar tool in the path '/stuff/apps/foobar', then run it".- By contrast,
warpforgeis 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!
wfxcan 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 installandwfx installwould both cause the respective tools to look for a target named "install", evaluate all its dependencies, and then evaluate that target. - different:
wfxuses Starlark syntax (aka, a Pythonic syntax). - different:
wfxhas "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 usemakein 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