Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Migrate CLI implementation to Rust#30

Merged
akriaueno merged 8 commits into
developfrom
rust-migration
May 30, 2026
Merged

Migrate CLI implementation to Rust#30
akriaueno merged 8 commits into
developfrom
rust-migration

Conversation

@akriaueno

@akriaueno akriaueno commented May 30, 2026

Copy link
Copy Markdown
Owner

Summary

  • Migrate the CLI implementation from Nim to Rust with a Cargo-based why binary
  • Port provider detection, symlink resolution, Flatpak fallback, and package-manager lookup tests
  • Update Nix packaging, Docker E2E builder, CI, release workflow, and Homebrew formula generation for Rust
  • Build Linux ARM64 releases on the native ubuntu-24.04-arm runner

Testing

  • cargo fmt --check
  • cargo clippy --all-targets -- -D warnings
  • cargo test --locked
  • nix build
  • nix shell nixpkgs#actionlint -c actionlint
  • ./tests/e2e/run.sh

Summary by CodeRabbit

  • Documentation

    • Updated "Build from Source" section with new commands; binary now output to ./target/release/why
    • Updated "Testing" instructions with new test commands
    • Updated dependency management guidance
  • Build Infrastructure

    • Updated CI/CD pipelines and GitHub Actions workflows
    • Updated Docker and Nix package configurations for the new build system

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 30, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@akriaueno, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 46 minutes and 41 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 492f0e50-5fc7-4ffd-9898-6e6a8708840e

📥 Commits

Reviewing files that changed from the base of the PR and between 41ab667 and 751b5c5.

📒 Files selected for processing (6)
  • .github/workflows/ci.yml
  • .github/workflows/release.yml
  • README.md
  • src/core.rs
  • tests/e2e/Builder.Dockerfile
  • tests/e2e/README.md
📝 Walkthrough

Walkthrough

This PR completes a language migration from Nim to Rust. The core resolution algorithm, CLI, project manifest, and all CI/CD workflows (GitHub Actions, Nix, Docker, Homebrew) transition to Rust equivalents, while build artifact ignores are updated for the new system.

Changes

Nim-to-Rust migration

Layer / File(s) Summary
Core resolution engine and types
src/core.rs
Introduces Rust types (MatchKind, ProviderRule, WhyCtx, WhyResult, WhyError), implements default provider rules, path normalization, symlink chain resolution with cycle detection, provider detection by pattern matching origin/real paths, system package-manager attribution (dpkg/rpm/apk/pacman/portage), Flatpak fallback lookup, and the main why_core orchestrator. Includes comprehensive unit tests covering origin detection, provider rules, package-manager integration, and symlink edge cases.
CLI entrypoint, runtime context, and manifest
src/main.rs, Cargo.toml, README.md
Rust CLI uses clap for parsing; DefaultCtx implements WhyCtx trait with filesystem/environment/PATH/command-execution helpers; main function calls why_core, outputs formatted results (hint, provider, paths), and reports errors with exit codes. Cargo.toml declares the crate and clap dependency. README updated with Rust build/test commands.
CI test and quality workflow
.github/workflows/ci.yml
Test job replaces Nim toolchain with Rust: installs Rust with clippy/rustfmt, caches Cargo, runs format and lint checks, executes cargo test --locked. New Nix build job added.
Release workflow, distribution, and Docker build
.github/workflows/release.yml, .github/scripts/generate_formula.sh, tests/e2e/Builder.Dockerfile
Release workflow converts to Rust cross-compilation: build matrix now defines Rust target, target_os, cpu, archive_name, optional install_cross/linker_env; installs stable Rust toolchain for targets, caches Cargo, builds via cargo build, packages tar.gz, and uploads via softprops/action-gh-release@v2. Homebrew formula script checks for Cargo.toml and generates formula with rust build dependency and cargo install --locked. Docker builder migrated from nimlang/nim to rust:1.90-bookworm, using cargo build --release --locked.
Nix package definition for Rust
nix/package.nix, nix/nim-lock.json
Nix derivation refactored from buildNimPackage to rustPlatform.buildRustPackage; function parameter changed from buildNimPackage to rustPlatform; lockfile wiring switched from ./nim-lock.json to ../Cargo.lock. Nim lock file removed.
Ignore patterns and artifact cleanup
.gitignore, .dockerignore
Updated to ignore Rust build output (/target/, result) and remove obsolete Nim test binary patterns; preserves ignores for why, why.exe, and E2E binaries.

Sequence Diagram

sequenceDiagram
  participant User as why_core
  participant Origin as find_origin_path
  participant Symlink as resolve_symlink_chain
  participant Detect as detect_provider_by_path
  participant PkgMgr as check_system_package_manager
  participant Result as WhyResult

  User->>Origin: locate command
  Origin-->>User: origin_path
  User->>Symlink: expand symlinks
  Symlink-->>User: real_path
  User->>Detect: match rules
  Detect-->>User: provider
  alt provider unknown
    User->>PkgMgr: query systems
    PkgMgr-->>User: attributed provider
  end
  User->>Result: build result
  Result-->>User: WhyResult or WhyError
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • akriaueno/why-cli#29: Both PRs modify nix/package.nix and nix/nim-lock.json; this PR migrates from Nim to Rust build, while #29 initially set up Nix for Nim.
  • akriaueno/why-cli#6: Both PRs refactor .github/workflows/release.yml; this PR converts Nim build to Rust cross-compilation, while #6 modifies Nim release steps.
  • akriaueno/why-cli#28: Both PRs extend provider/path detection and system package-manager logic; #28 enhances the Nim why_core, while this PR rewrites those functions in Rust as default_rules, detect_provider_by_path, and check_system_package_manager.

Poem

🐰 From Nim's swift streams to Rust's strong shore,
The CLI leaps where it lived before.
Symlinks unspool, providers align—
One language gone, one language shines.
Cross-platforms bound in Cargo's embrace,
Why runs faster in a safer place! 🦀

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.39% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Migrate CLI implementation to Rust' clearly and directly summarizes the main change: converting the project from Nim to Rust, which is the primary focus across all modified files (Cargo.toml, src/main.rs, src/core.rs, removal of .nim files, and updated tooling).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch rust-migration

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (1)
tests/e2e/Builder.Dockerfile (1)

1-1: ⚡ Quick win

Pin the Rust builder image to a digest.

rust:1.90-bookworm will drift as upstream images are rebuilt, so E2E failures become harder to reproduce and the exact toolchain provenance is lost.

Example
-FROM rust:1.90-bookworm
+FROM rust:1.90-bookworm@sha256:<published-digest>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/e2e/Builder.Dockerfile` at line 1, The FROM line uses the mutable tag
rust:1.90-bookworm; replace it with the corresponding immutable digest (e.g.
rust@sha256:...) to pin the builder image so the Rust toolchain no longer drifts
— locate the FROM instruction referencing "rust:1.90-bookworm" in
Builder.Dockerfile and update it to the image digest form fetched from the
upstream registry.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/ci.yml:
- Around line 25-31: Replace unpinned, tag-based GH Actions and enable
non-persisted checkout for the Nix step: pin dtolnay/rust-toolchain,
Swatinem/rust-cache, cachix/install-nix-action and actions/checkout references
to specific commit SHAs (not tags) and in the checkout step used for Nix set
persist-credentials: false; update any existing uses of actions/checkout@v4 to
the pinned SHA and add persist-credentials: false under the checkout step that
prepares the Nix environment so the auth token is not persisted.

In @.github/workflows/release.yml:
- Around line 55-56: Update the "Cache Cargo" step that uses
Swatinem/rust-cache@v2 to make the cache read-only for the tag-triggered release
workflow by adding the input flag to disable saving (set save-if: false) under
the step's with: section so the action will not write or update the cache during
this privileged job.
- Around line 50-56: Replace the mutable action tags in the release workflow
with pinned commit SHAs: change dtolnay/rust-toolchain@stable,
Swatinem/rust-cache@v2, and softprops/action-gh-release@v2 to their respective
commit SHA refs so the workflow uses exact commits instead of tags;
additionally, for the Swatinem/rust-cache step (the action named "Cache Cargo")
add the configuration to disable writes (e.g., set the save-if / restore-only
equivalent such as with: save-if: "false" or the action's restore-only option)
so the release run only restores cache and never updates it.

In `@README.md`:
- Around line 133-139: Replace the incorrect markdown link syntax in the bash
example so the git clone command is a valid shell command: change the line
containing "git clone
[https://github.com/akriaueno/why-cli.git](https://github.com/akriaueno/why-cli.git)"
to use a plain URL after git clone (i.e., `git clone
https://github.com/akriaueno/why-cli.git`) so copy/pasting the README's setup
steps works as intended.

In `@src/core.rs`:
- Around line 348-355: The check that decides to use the Flatpak fallback
incorrectly treats explicit paths like "/usr/bin/ls" as missing because
file_name(&origin_path) != command_name; update the conditional in
find_origin_path so it first detects if the original command_name is an explicit
path (contains path separator or starts with '.'), and only perform the
file_name comparison or call find_flatpak_fallback when command_name is not a
path; in other words, skip the file_name(&origin_path) != command_name branch
for explicit paths and fallback to flatpak only when origin_path.is_empty() or
the non-path command's file_name doesn't match.
- Around line 66-72: The pattern list used by detect_provider_by_path contains a
case-mismatched entry "/usr/local/cellar" which will not match Intel macOS
Homebrew installs; update the patterns array (the patterns variable used in
detect_provider_by_path in src/core.rs) to use the correct casing
"/usr/local/Cellar" so the path comparison can match Intel Homebrew prefixes.

---

Nitpick comments:
In `@tests/e2e/Builder.Dockerfile`:
- Line 1: The FROM line uses the mutable tag rust:1.90-bookworm; replace it with
the corresponding immutable digest (e.g. rust@sha256:...) to pin the builder
image so the Rust toolchain no longer drifts — locate the FROM instruction
referencing "rust:1.90-bookworm" in Builder.Dockerfile and update it to the
image digest form fetched from the upstream registry.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8b2c3130-ced5-40ca-8c77-a5493cf3a378

📥 Commits

Reviewing files that changed from the base of the PR and between 27ebecb and 41ab667.

⛔ Files ignored due to path filters (2)
  • Cargo.lock is excluded by !**/*.lock
  • nimble.lock is excluded by !**/*.lock
📒 Files selected for processing (17)
  • .dockerignore
  • .github/scripts/generate_formula.sh
  • .github/workflows/ci.yml
  • .github/workflows/release.yml
  • .gitignore
  • Cargo.toml
  • README.md
  • nix/nim-lock.json
  • nix/package.nix
  • src/core.rs
  • src/main.rs
  • src/why.nim
  • src/why_core.nim
  • src/why_os.nim
  • tests/e2e/Builder.Dockerfile
  • tests/test_why_core.nim
  • why_cli.nimble
💤 Files with no reviewable changes (6)
  • why_cli.nimble
  • src/why.nim
  • src/why_core.nim
  • tests/test_why_core.nim
  • src/why_os.nim
  • nix/nim-lock.json

Comment thread .github/workflows/ci.yml Outdated
Comment thread .github/workflows/release.yml Outdated
Comment thread .github/workflows/release.yml Outdated
Comment thread README.md
Comment thread src/core.rs
Comment thread src/core.rs Outdated
@akriaueno akriaueno merged commit 5c2409d into develop May 30, 2026
7 checks passed
@akriaueno akriaueno deleted the rust-migration branch May 30, 2026 13:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant