Hi,
I am interested in Rust task runners. While make is fine for basic projects of various programming languages, there is a level of rigor and portability in using primarily Rust code as opposed to shell commands. I want my build system declared in the very same language as the main application/library.
There is a trend for exactly that:
- Go has mage.
- Haskell has Shake.
- NPM can do this with the booty pattern.
- C/C++ can do this with rez (deprecated).
- D can do this with dale (deprecated).
- Groovy can probably do this with Gradle.
- Clojure can probably do this with Leiningen.
- Scala can probably do this with sbt.
- Rust can do this with tinyrick.
cargo build scripts can nearly do this. However, it is missing several essential features present in conventional task runners:
- cargo build scripts are tightly coupled to the overall compilation step, meaning non-contributors would be forced to install extra libraries and/or tools for non-compilation needs. Linters, Remote deployment tools, VM's, integration tests... Such tools belong in dev environments strictly for people actively modifying a Rust project's code, not downstream users. It's one thing to require a C++ compiler for FFI projects, or Thrift, or other code generation systems. Another thing entirely to require Python, or whatever kitchen sink suite that projects inevitably end up consuming.
- cargo build scripts have no way to invoke the scripts other than performing a cargo compilation command. There's no
make <your-task-here>. - There's no built-in mechanism for declaring logical task dependencies on other tasks, to prevent redundant tasks from being called twice.
A million and one task runners also exist, using INI/JSON/YAML/TOML to declare tasks, in a way that is even more baroque than make. Super not a fan of those. There's no way to directly trigger programming language functions. Thus incurring portability, safety, and performance costs. Embedding shell commands in non-shell files breaks SAST scans, so those should be kept to a minimum.
That's why I wrote tinyrick. It lets us declare tasks for linting, fuzzing, and other non-build steps out of band of the cargo compilation system. So that we can extend development and CI/CD processes, without breaking conventional build commands.
The task dependency relationship and caching system consists of a simple hashmap. Either the task has been called yet, or it hasn't. No need for fancy graph traversal.
All tasks are effectively .PHONY: by default, with no default tasks. As opposed to make's deep C, lex, and yacc logic.
tinyrick (and tinyrick_extras) provide practical functions and macros for invoking shell commands. Though the emphasis is on calling your custom Rust code for dev tasks, whenever possible.
I am a Zenful programmer: My absolute favorite thing to do in programming is delete lines of code. I would very much like to deprecate tinyrick entirely, in favor of some sufficiently clean, community maintained equivalent, should one exist.
What are some currently maintained, 0 CVE Rust equivalents to Go's mage?