Sign inSign up

cutsea110/cargo-anatomy

By cutsea110

•Updated 22 days ago

`cargo-anatomy` analyzes Rust workspaces and calculates inter-packages metrics

Image
Developer tools
0

7.5K

cutsea110/cargo-anatomy repository overview

⁠cargo-anatomy

Cargo Anatomy Logo

Rust CI Crates.io Crates.io Downloads Docker Cloud Build Status

cargo-anatomy analyzes Rust workspaces and calculates metrics inspired by Robert C. Martin's package metrics. Each crate inside the workspace is treated as a package.

⁠Installation

cargo install cargo-anatomy

⁠Metrics

  • N — number of classes in the crate (struct, enum, trait and type definitions).
  • R — number of internal class relationships. Each unique reference from one class to another within the same crate counts once.
  • H — relational cohesion: H = (R + 1) / N.
  • Ca — afferent coupling: the number of external classes that depend on types from this crate.
  • Ce — efferent coupling: the number of classes in this crate that depend on types from other crates in the workspace.
  • A — abstraction: ratio of abstract classes (traits) to total classes, A = abstract_classes / N.
  • I — instability: I = Ce / (Ce + Ca).
  • D — distance from the main sequence: D = |A + I - 1| / sqrt(2).
  • D' — normalized distance from the main sequence: D' = |A + I - 1|.

⁠Evaluation

Each metric is also mapped to a qualitative label. These labels are assigned using the following thresholds:

  • A (abstraction): ≥ 0.7 is abstract, ≤ 0.3 is concrete, otherwise mixed.
  • H (cohesion): > 1.0 is high, otherwise low.
  • I (instability): ≥ 0.7 is unstable, ≤ 0.3 is stable, otherwise moderate.
  • D' (normalized distance):
    • ≤ 0.4 → good.
    • ≥ 0.6 → useless if A + I - 1 ≥ 0, otherwise painful.
    • otherwise balanced. cargo-anatomy also reports the list of classes discovered in each crate and detailed dependency graphs when invoked with the -a flag.

⁠Usage

# Run on the current workspace
cargo anatomy

# Show detailed class and dependency information
cargo anatomy -a

# Include external dependencies in metrics (may be slower)
cargo anatomy -x

# Use a custom evaluation config generated by `cargo anatomy init` below
cargo anatomy -c config.toml

# Generate a template config file which you can modify and use with `-c`
cargo anatomy init

# Display help with metric descriptions
cargo anatomy -?

# Show version
cargo anatomy -V

# Output in YAML format
cargo anatomy -o yaml
# Output in Graphviz DOT format
cargo anatomy -o dot
# Output in Mermaid format
cargo anatomy -o mermaid

# Fail if metrics violate thresholds (experimental)
cargo anatomy --h-lt 1.1 --d-prime-ge 0.9

For custom evaluation thresholds, run cargo anatomy init to generate a template configuration and pass -c <FILE> to load it. See the Configuration⁠ section for more details.

The command outputs metrics for every member crate in compact JSON format by default. Use -x to also analyze external dependencies. Analyzing external crates can significantly increase processing time. When the -a flag is used, each crate also includes a details.kind field indicating whether it is part of the workspace or an external crate. Pipe to jq if you want it pretty printed. Use -o yaml for YAML output, -o dot for Graphviz or -o mermaid for Mermaid diagrams. When using -o dot, you can write the graph to a file and convert it with Graphviz: cargo anatomy -o dot > graph.dot && dot -Tpng graph.dot -o graph.png. Dependency arrows are labeled with the efferent couple count from the source crate when the -a flag is used. Graphviz and Mermaid diagrams can include individual type nodes when --show-types-crates=<CRATE1,CRATE2> is specified. Mermaid will only render the first 500 edges by default, so increase maxEdges in your Mermaid configuration⁠ if your graph is larger. Both Graphviz and Mermaid outputs omit dependency edges unless -a is supplied, so combining these formats with -a is recommended when you want to visualize the graph.

See docs/output-schema.md⁠ for a description of the output schema. Example output (| jq):

{
  "meta": {
  "cargo-anatomy": { "version": "0.6.0", "target": "linux/x86_64" },
    "config": {
      "evaluation": {
        "abstraction": { "abstract_min": 0.7, "concrete_max": 0.3 },
        "cohesion": { "high_gt": 1.0 },
        "instability": { "unstable_min": 0.7, "stable_max": 0.3 },
        "distance": { "good_max": 0.4, "bad_min": 0.6 }
      }
    }
  },
  "crates": [
    {
      "crate_name": "my_crate",
      "metrics": {
        "n": 3,
        "r": 1,
        "h": 0.67,
        "ca": 0,
        "ce": 1,
        "a": 0.33,
        "i": 1.0,
        "d": 0.24,
        "d_prime": 0.34
      },
      "evaluation": {
        "a": "mixed",
        "h": "low",
        "i": "unstable",
        "d_prime": "good"
      },
      "details": {
        "kind": "Workspace",
        "classes": [
          { "name": "Foo", "kind": "Struct" },
          { "name": "Bar", "kind": "Struct" },
          { "name": "MyTrait", "kind": "Trait" }
        ]
      }
    }
  ],
  "warnings": {
    "dependency_cycles": []
  }
}

Enable RUST_LOG=info to see progress logs during analysis.

⁠Configuration

cargo-anatomy looks for a .anatomy.toml file at the workspace root to customize how metric values are evaluated. Run cargo anatomy init to create a template .anatomy.toml in the current directory. Pass -c <FILE> to use a different configuration. The file is written in TOML and contains the following sections and defaults:

[evaluation]
  [evaluation.abstraction]
  abstract_min = 0.7   # minimum ratio considered abstract
  concrete_max = 0.3   # maximum ratio considered concrete

  [evaluation.cohesion]
  high_gt = 1.0        # values greater than this are high cohesion

  [evaluation.instability]
  unstable_min = 0.7   # minimum ratio considered unstable
  stable_max = 0.3     # maximum ratio considered stable

  [evaluation.distance]
  good_max = 0.4       # max normalized distance considered good
  bad_min = 0.6        # min normalized distance considered bad

Specify a path with -c <FILE> to use a different configuration, or omit the option to rely on these defaults.

⁠Docker image

⁠Using the official image

A pre-built container is available on Docker Hub. Replace <version> with the desired tag and mount your workspace into /work:

docker run --rm -v $(pwd):/work cutsea110/cargo-anatomy:<version> [ARGS...]

Any arguments after the image name are forwarded to cargo-anatomy. The image includes the toolchain cargo binary and sets the CARGO environment variable to that path, so cargo metadata works without rustup.

⁠Building an image (for developers)

Build an image for the current architecture and load it into Docker with:

docker buildx build --platform <arch> -t cargo-anatomy --load .

Replace <arch> with linux/amd64 on x86_64 machines or linux/arm64 on Arm-based hosts. To publish a multi-platform image, use --push instead of --load:

docker buildx build --platform linux/amd64,linux/arm64 \
    -t <your-registry>/cargo-anatomy:<version> --push .

Set <version> to the tag for the published image. After building or pulling an image, run it as shown above. The runtime uses a distroless base for a smaller footprint.

⁠GitHub Actions

You can integrate cargo-anatomy in your CI pipeline. The example below installs cargo-anatomy and fails the job when metrics do not satisfy the configured thresholds. Make sure a .anatomy.toml file is present in your repository so the workflow can load your evaluation settings. You can generate a template with cargo anatomy init and commit it to version control.

# .github/workflows/anatomy.yml
name: cargo-anatomy

on:
  push:
    branches: [ main ]
  pull_request:

jobs:
  analyze:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-rust@v1
        with:
          rust-version: stable
      - name: Install cargo-anatomy
        run: cargo install cargo-anatomy
      - name: Run cargo-anatomy
        run: cargo anatomy -c .anatomy.toml --h-lt 1.1 --d-prime-ge 0.9

Tag summary

Content type

Image

Digest

sha256:0729d73c1…

Size

25.7 MB

Last updated

22 days ago

docker pull cutsea110/cargo-anatomy