packs

WIP Rust implementation of packwerk for ruby
About
- It's entirely built in Rust, so it's pretty fast! In Gusto's monolith, it's about 10x faster (Benchmarks) than the ruby implementation. Your mileage may vary! Other performance optimizations could potentially get to 20x faster.
- The goal is for this to be able to be a drop-in replacement for
packwerk. - Currently,
packsimplementscheckandupdate.
Usage
Once installed and added to your $PATH, just call packs to see the CLI help message.
Verification
As packs is still a work-in-progress, it's possible it will not produce the same results as the ruby implementation (see below). If not, please file an issue!
To verify:
- Follow directions below to get the
packsbinary - Run
rm -rf tmp/cache/packwerkto delete the existing cache. - Option 1: Run
packs check(there should be no violations) - Option 2: Run
packs update(there should be no diff)
Downloading the Binary
Distribution ergonomics are still a WIP.
If you want to try it out:
- Go to https://github.com/alexevanczuk/packs/releases
- Download the
packsasset and runchmod +x path/to/packs - Open the containing directory, right click on the binary, click open, and then accept the warning message that says its from an unknown developer (it's me!)
- Execute
path/to/packsto see the CLI help message.
You can add path/to/packs to your PATH so it's available in every terminal session.
Currently, the uploaded binary file is built for macOS. If you want to try it on another platform, you'll need to build it yourself, or just let me know (e.g. file an issue) you're interested in trying it, what platform you're using, and I'll upload a binary for you.
Distribution Improvements
In the future, I hope to:
- Somehow sign the binary so it does not get a warning message
- Make it executable before download
- Add directions to download via some other tool, or ship as a native ruby gem extension.
New to Rust?
Me too! This is my first Rust project, so I'd love to have feedback, advice, and contributions! If you're new to Rust, don't be intimidated! https://www.rust-lang.org has tons of great learning resources.
Not yet supported:
- privacy checker or other checkers
- custom associations
- custom inflections
- custom load paths
- zeitwerk default namespaces
- extensible plugin system
- stale violation detection
- bin/packwerk validate (e.g. cycle detection)
Benchmarks
Cold Cache, without Spring
packs check:rm -rf tmp/cache/packwerk && DISABLE_SPRING=1 time ../pks/target/release/packs checkpackwerk check:rm -rf tmp/cache/packwerk && DISABLE_SPRING=1 time bin/packwerk check
| Run | packs check |
packwerk check |
|---|---|---|
| 1 | 8.9s | 107.83s |
| 2 | 7.31s | 85.24s |
| 3 | 7.55s | 126.52s |
| 4 | 6.85s | 80.47s |
| 5 | 8.45s | 99.90s |
| Average | 7.812s | 99.99s |
Hot Cache, without Spring
packs check:DISABLE_SPRING=1 time ../pks/target/release/packs checkpackwerk check:DISABLE_SPRING=1 time bin/packwerk check
| Run | packs check |
packwerk check |
|---|---|---|
| 1 | 3.86s | 39.33s |
| 2 | 3.69s | 34.02s |
| 3 | 3.6s | 41.68s |
| 4 | 3.52s | 35.26s |
| 5 | 3.32s | 37.14s |
| Average | 3.598 | 37.29 |
Profiling
I've been using https://github.com/flamegraph-rs/flamegraph to generate flamegraphs to improve performance.
Specifically, this command which merges similar code paths to see where most of the time is spent:
sudo cargo flamegraph --profile=release --reverse --min-width=0.5 -- --project-root=../your_app check
For more, see: https://nnethercote.github.io/perf-book/profiling.html
Local Development
Running the CLI in release mode against a target app
RUST_LOG=debug time cargo run --profile=release -- --project-root=../your_app check