Let's build a ruleset for Bazel! Introducing rules_nushell

Hey there, my dear apprentice in the dark arts of Bazel, it is my pleasure to make your acquaintance. I wonder what brought you here in the first place... Were you curious about building rules with Bazel? Or were you looking for cross-platform genrules? Or did a so-called "friend" of yours link you to this blog? Alas, it doesn't matter, what's done is done and now that you're here, I better get started!

A short introduction to Bazel and rulesets

Maybe you don't even know what Bazel is in the first place, but we can fix this together. Bazel is a build system developed internally at Google for more than a decade. It offers scalability, reliability and speed that few others can. It is completely open-source (though its initial closed-source version - Blaze - is still very much alive and active internally in Google) and supports a plethora of different programming languages.

But how does it do so? Well, bazel allows you to extend its built-in capabilities through a language called starlark, a much simpler cousin of python. In truth, it's through this extension mechanism that most languages are supported. In Bazel you define how builds work through rules. Each rule is responbible of defining how to generate outputs and providing additional build metadata (eg: the java_binary rule defines how to generate a java executable from java source code and libraries). A set of rules for a specific language/technology is called a ruleset and this is what we are going to build together.

Before reading through this series though I vividly recommend going through Bazel's getting started guides.

Why nushell?

So why should we integrate nushell out of all the possible shells? Well, first of all, nushell is completely cross-platform. Secondly, it's a data-oriented shell, meaning that everything in nushell is structured data and has really powerful, simple and fast facilities to extract, manipulate and output data. The underlying language it employs is also extremely flexible and extendable, making it a good solution to future-proof your builds. Even better, it is shipped as a single binary for all the platforms, making it easier to integrate with Bazel.

What to expect from this series?

Our first goal will be to create a more interactive and reproducible genrule based on nushell. genrule as the name hints, is a very generic rule that allows you to execute a script and generate some outputs from it. Sadly this isn't very portable and has historically been a code smell and a hindrance to reproducibility. This is because it relies on the system's installed bash for linux/mac. This makes it hard to write genrules that behave consistently as different users can have different shells installed. Not only that, but unlike most of the platforms using shell scripting, Bazel does not provide a great interactive experience as you can't simply spawn an interactive shell with the same environment as the genrule you are writing to test out parts of the script.

We will also look into creating portable libraries and binaries using the nushell scripting language and then we will see how to implement a hermetic toolchain.

Finally, we will look into the various options we have to share this ruleset with our users, how to add tests and documentation.

Great, can I help or follow along?

Yeah, you sure can! You can find rules_nushell on github under an Apache License 2.0 license. Contributions, suggestions and feedback are extremely welcome!