# packs



WIP Rust implementation of [packwerk](https://github.com/Shopify/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](#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, `packs` implements `check` and `update`.
# 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 `packs` binary
- Run `rm -rf tmp/cache/packwerk` to 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 `packs` asset and run `chmod +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/packs` to 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](https://www.rust-lang.org/learn) 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 check`
- `packwerk check`: `rm -rf tmp/cache/packwerk && DISABLE_SPRING=1 time bin/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 check`
- `packwerk check`: `DISABLE_SPRING=1 time bin/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
```