Skip to content

gabadi/drywall

Repository files navigation

drywall

Polyglot AST subtree DRY analyzer. Detects duplicate code across files using Jaccard similarity over normalized AST fingerprints.

A Rust port of unclebob/dry4go, extended to work across Rust, JavaScript, TypeScript, and Python (dry4go is Go-only).

Install

# Rust
cargo install drywall

# Python
pip install drywall
# or, without installing:
uvx drywall ./src

# Node.js
npm install --save-dev drywall-cli
# then: npx drywall ./src, or add a package.json script

Or download the binary for your platform from the latest release:

Platform Binary
Linux x86_64 drywall-linux-x86_64
macOS Apple Silicon drywall-macos-aarch64
macOS Intel drywall-macos-x86_64
# Linux
curl -sL https://github.com/gabadi/drywall/releases/latest/download/drywall-linux-x86_64 -o drywall
chmod +x ./drywall

# macOS Apple Silicon
curl -sL https://github.com/gabadi/drywall/releases/latest/download/drywall-macos-aarch64 -o drywall
chmod +x ./drywall

# macOS Intel
curl -sL https://github.com/gabadi/drywall/releases/latest/download/drywall-macos-x86_64 -o drywall
chmod +x ./drywall

The Linux binary is statically linked (musl) — no runtime dependencies.

Usage

drywall [--threshold 0.82] ./src

--threshold is the Jaccard similarity cutoff (default 0.82, same as dry4go). Pairs at or above the threshold are reported. Exit codes: 0 = no duplicates, 1 = duplicates found, 2 = bad arguments.

Use as a CI gate

Add to any project's CI pipeline:

- name: Install drywall
  run: |
    curl -sL https://github.com/gabadi/drywall/releases/latest/download/drywall-linux-x86_64 -o drywall
    chmod +x ./drywall

- name: DRY check
  run: ./drywall --threshold 0.82 ./src

--threshold sets the Jaccard similarity cutoff (default 0.82). Pairs at or above the threshold are flagged. The step fails (exit 1) if any duplicates are found.

Build from source

Requires Rust 1.96+:

cargo build --release
./target/release/drywall ./src

Release process

  1. Bump the version in Cargo.toml.
  2. Commit, tag, and push:
    git commit -am "chore: release vX.Y.Z"
    git tag vX.Y.Z
    git push origin main
    git push origin vX.Y.Z
  3. The release workflow triggers on the tag push: it builds the platform binaries, creates the GitHub Release, and publishes to crates.io and PyPI automatically (crates.io via CARGO_REGISTRY_TOKEN, PyPI via trusted publishing).
  4. Publish to npm manually (not automated — this account requires a one-time password on every publish, which CI can't provide):
    ./scripts/publish-npm.sh vX.Y.Z
    npm will prompt for an OTP once per package (4 packages total).

About

Polyglot DRY analyzer — AST subtree hashing + Jaccard similarity for Rust, JS/TS, and Python

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors