| Crates.io | brix |
| lib.rs | brix |
| version | 0.4.2 |
| created_at | 2022-02-12 22:28:47.523973+00 |
| updated_at | 2024-01-25 22:32:23.538943+00 |
| description | Brix is a CLI tool written in Rust for scaffolding and code generation. |
| homepage | https://github.com/xenoterracide/brix |
| repository | https://github.com/xenoterracide/brix |
| max_upload_size | |
| id | 531518 |
| size | 110,552 |
Brix is a CLI tool written in Rust for scaffolding and code generation.
Special thanks to Caleb Cushing for the original Java version, early interface design and internal architecture.
Brix is available on crates.io and the AUR for Arch Linux.
Install with cargo:
cargo install brix
Arch Linux (use an AUR helper like yay or trizen)
yay -S brix-git
Usage:
brix [LANGUAGE] [CONFIG NAME] [PROJECT] [MODULE]
brix [OPTIONS] --config-dir | -d [CONFIG DIRECTORY]
brix [OPTIONS] --workdir | -w [WORKING DIRECTORY]
cargo buildcargo runRun cargo test --all to test the entire workspace.
Run cargo doc --no-deps --workspace --document-private-items --open
To start using Brix in your project, create a .config/brix directory in your project.
This directory will contain your configuration files. Specifying the first argument after running brix will tell it which subdirectory to use. For example, starting Brix with brix java will search the .config/brix/java directory for configuration files in your project. This parameter is known as the language. If a config file isn't found, Brix will move up to the parent directory all the way up to HOME, until it finds a directory that contains a .config/brix/java. This parameter doesn't necessarily have to be resitrcted to a programming language, it's there to group configuration files used in a similar way, perhaps for bootstraping a specific project.
Of course, running brix [language] without pointing Brix to a specific config file is a bit useless. The second argument specifies the file name to use. Running brix java tutorial will search for a file in .config/brix/java named tutorial.brix.yml or tutorial.brix.yaml. As of right now the files must be written in YAML, but more options will be supported in the future, like JSON and TOML.
These two arguments are specific to your config file, you can use them however you want, so let's take a look at how the config file is structured first.
Brix offers various commands for you to use to scaffold and generate your project. At the top-most level, the config file is just a list of commands, therefore we can start by just declaring the commands property:
# example.brix.yml
commands:
- search_replace:
# ...
- exec:
# ...
The commands you list will be executed from top to bottom, one after the other. The following commands are supported:
copy
Copies a file or directory to a new location.
search_replace
Searches for a strin or regular expression in a file and replaces it with another string.
exec
Executes a list of commands.
mkdir
Creates a directory.
template
Templates a file to a new location.
Let's start with the most basic copy command, and use Brix to simply copy a .gitignore file. Our config file would look something like this:
# .config/brix/js/gitignore.brix.yml
commands:
- copy:
source: .gitignore
destination: app/.gitignore
The source directory is always relative to where the config file is located. In this case it would be .config/brix/js/.gitignore. The destination directory is relative to where you run brix from, this is also known as the working directory, and can be overriden with the --workdir or -w flag.
Now, if we were to run brix js gitignore in our project directory, we would actually get an error.
That's because Brix requires the project and module arguments to be specified.
In our case, we're not using them yet so we can specify anything. Now, running brix js gitignore project module will run the command. If you didn't already have an app directory, Brix will create one for you and copy the .gitignore file to it.
You might notice though that this isn't that convenient for our project if we wan't to put the file somewhere other than app. Let's say now we have a backend folder in addition to app. To copy the .gitignore file to backend, we would have to change the destination in the config file each time. Instead, this is where the project and module arguments come in handy. Let's change the config file to:
# .config/brix/js/gitignore.brix.yml
commands:
- copy:
source: .gitignore
destination: {{project}}/.gitignore
Here, we are using the project argument in the destination.
Running brix js gitignore backend module will now copy the file to backend/.gitignore. If we wanted to copy it to somewhere else, all we would have to do is run brix js gitignore somewhere_else module.
We could also use the module parameter to, for example, sample a different gitignore file.
# .config/brix/js/gitignore.brix.yml
commands:
- copy:
source: {{module}}/.gitignore
destination: {{project}}/.gitignore
Running brix js gitignore dashboard default will use .config/brix/js/default/.gitignore and copy it to dashboard/.gitignore.
Now, let's take a full look at all of the commands.
commands:
- copy:
source: file.txt
destination: output/file.txt
overwrite: true # Optional, will ask by default to overwrite if the file already exists
Search replace uses fancy regex for regular expressions in the search field and supports backreferences. The syntax is best explained here.
commands:
- search_replace:
destination: file-to-search-replace.txt
search: search string # fancy-regex supported
replace: replace string
Executes commands in order.
commands:
- exec:
commands:
- 'echo "Hello World!"'
- "prettier --write ."
- "cargo --version"
stdout: true # Optional
Creates a directory.
commands:
- mkdir:
destination: output/directory
Templates a file.
commands:
- template:
source: file.ex.hbs
destination: output/file.ex
overwrite: true # Optional
context: # Optional
first: {{project}}Service
second: {{module}}
file.ex.hbs could look something like:
defmodule App.{{first}.{{second}} do
# ...
end
And when templated, output/file.ex:
defmodule App.UsersService.Store do
# ...
end
Brix uses Handlebars, specifically the Rust version with both the template command and config files in general. The context parameter in the command isn't required, since {{project}} and {{module}} are automatically handled if specified in the template file.
There's also a way to specify global context in the config file:
context:
edition: 2022
name: {{project}}
commands:
- template:
source: file.txt.hbs
destination: output/file-{{edition}}.txt
- copy:
source: {{edition}}/notes.txt
destination: output/notes.txt
In this case, parameters edition, name, project, and module will all be available for use within the config file itself and all template files referenced in template commands. Global context is also useful for declaring constants that are shared between multiple commands.
Brix also provides useful helpers for manipulating these variables, specifically for altering capitalization and case. The following helpers are provided:
to-upperto-lowerto-titleto-caseto-flatto-java-packageto-java-package-pathAll of these can be used to replace, for example, usage of {{project}}:
context:
project: 'foo BAR 40'
{{to-upper project}} # FOO BAR 40
{{to-lower project}} # foo bar 40
{{to-title project}} # Foo Bar 40
{{to-flat project}} # foobar40
{{to-java-package project}} # foo.bar40
{{to-java-package-path project}} # foo/bar40
Brix has the added benefit of not requiring a specific folder structure to be used inside the language directories. Templates and other files are completely independent from config files. This means that reusing templates is a lot easier, as everything is referenced with just a path. If you need to use the same template within two different config files, simply reference the path to the file in both and use a different context.
Finally, let's take a look at a full example using Brix to bootstrap a Java project. The .config/brix directory is conveniently located in HOME in order to be able to run brix from anywhere and create a project like this.
commands:
- copy: # Copy all of the shared files to the project directory
source: project/shared
destination: .
overwrite: true
- template: # Template build.gradle.kts
source: module/build.gradle.kts.hbs
destination: "module/{{module}}/build.gradle.kts"
overwrite: false
- template: # Template module-info.java
source: module/src/main/java/module-info.java.hbs
destination: "module/{{module}}/src/main/java/module-info.java"
overwrite: false
- template: # Teplate package.json
source: project/templates/shared/package.json.hbs
destination: "package.json"
overwrite: false
- template: # Template settings.gradle.kts.hbs
source: project/templates/shared/settings.gradle.kts.hbs
destination: "settings.gradle.kts"
overwrite: false
- mkdir: # Create the main directory for the module
destination: "module/{{module}}/src/main/java/com/example/{{module}}"
- mkdir: # Create the test directory for the module
destination: "module/{{module}}/src/test/java/com/example/{{module}}"
- exec: # Run the following commands with no stdout
commands:
- git init
- git add .
- git commit -m initial
- yarn up
stdout: false
There are a few extra examples located in ./config/brix/rust.
cargo run -- rust copy brix foocargo run -- rust exec foo foocargo run -- rust mkdir brix foocargo run -- rust search_replace brix foocargo run -- rust template brix foo