Skip to content

bundle: install cargo packages from a git URL or path - #23451

Merged
MikeMcQuaid merged 6 commits into
Homebrew:mainfrom
tftio:cargo-source-option
Aug 7, 2026
Merged

bundle: install cargo packages from a git URL or path#23451
MikeMcQuaid merged 6 commits into
Homebrew:mainfrom
tftio:cargo-source-option

Conversation

@tftio

@tftio tftio commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

  • Have you followed our Contributing guidelines?
  • Have you checked for other open Pull Requests for the same change?
  • Have you explained what your changes do? Performance claims (e.g. "this is faster") must include Hyperfine benchmarks.
  • Have you explained why you'd like these changes included, not just what they do?
  • For bug fixes, have you given step-by-step brew commands to reproduce the bug?
  • Have you written new tests (excluding integration tests)? Here's an example.
  • Have you successfully run brew lgtm (style, typechecking and tests) locally?

  • I did not use AI/LLM to create this PR, or I disclosed the tool/model below and reviewed its output; I did not attribute commits to AI and will answer maintainer questions and review comments myself without AI/LLM.

Disclosed: this change was drafted with Claude Code (Claude Opus 5) and reviewed by me before opening. Verification is described under "How this was verified" below; commits are not attributed to AI.


What

cargo "name" can currently only install from crates.io. This adds an optional source: naming either a git URL or a local path:

cargo "ripgrep"
cargo "bat", source: "https://github.com/sharkdp/bat"
cargo "my-tool", source: "/Users/me/src/my-tool"

A git source installs with cargo install --git, a path source with cargo install --path. The option mirrors the uv extension's existing source:, and the accepted forms are the same set uv accepts (a URL scheme, or a path beginning /, ./ or ../); anything else is rejected when the Brewfile is parsed rather than being passed to cargo to fail obscurely.

brew bundle dump round-trips these, because cargo install --list reports the origin of anything not installed from a registry. Two details in the parsing are worth calling out for review:

  • The resolved commit that cargo appends as #<sha> is dropped, so that a dumped entry compares equal to a hand-written one and brew bundle check does not report an endless diff.
  • A branch, tag or revision chosen at install time is reported by cargo as a URL query (?branch=, ?tag=, ?rev=, never more than one) and is restored via the matching cargo install flag. --git does not accept a query — it hands the string to git verbatim, which fails — so this mapping is what makes a dumped Brewfile for a pinned crate actually installable.

Why

Installing a crate straight from a repository is a normal thing to do — private crates that were never published, and forks or unreleased fixes of public ones — but such crates currently cannot be expressed in a Brewfile at all. They are silently absent from brew bundle dump output, so a Brewfile that looks complete is not, and restoring a machine from it leaves those binaries missing.

How this was verified

brew lgtm passes (typecheck, style --changed, tests --changed). Beyond the unit tests, the source parsing and flag reconstruction were checked against real cargo rather than only against mocks: a throwaway crate was installed from a local git repository via --branch, --tag and --rev into isolated roots, and the cargo install --list output for each was fed back through the parser. The reconstructed cargo install --locked --git <url> --branch <name> <crate> was then executed, and the resulting install --list entry is byte-identical to the one that produced it, so dump and restore is a fixed point.

Known limits, deliberately left alone to keep this consistent with uv: ~ is not expanded in a path source (Bundle.system does not go through a shell), and a bare relative path such as src/foo is not accepted, since it is ambiguous with a crate name.

🤖 Generated with Claude Code

`cargo "name"` could only install from crates.io. Accept a `source:`
option naming a git URL or a local path, mirroring the `uv` extension,
and install with `cargo install --git` or `cargo install --path`.

`cargo install --list` reports the origin of anything not installed
from a registry, so dumped Brewfiles round-trip. The resolved commit is
dropped, since a dumped entry has to compare equal to a hand-written
one, while a branch, tag or revision chosen at install time is carried
in the URL query and restored with `--branch`, `--tag` or `--rev`.
@tftio
tftio marked this pull request as ready for review August 5, 2026 18:05
Copilot AI lite review requested due to automatic review settings August 5, 2026 18:05

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR extends Homebrew Bundle’s cargo support so Brewfiles can install Rust crates from either crates.io (default) or an explicit source: pointing at a git remote or local path, and ensures brew bundle dump round-trips those origins.

Changes:

  • Adds source: parsing/validation for cargo Brewfile entries and passes it through install/check flows.
  • Enhances cargo install --list parsing to capture and dump non-registry origins, stripping resolved #<sha> while preserving ?branch=?tag=?rev= selectors.
  • Updates bundle documentation and expands unit test coverage for source-based cargo installs/dumps.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
Library/Homebrew/bundle/extensions/cargo.rb Implements source: handling, origin parsing/normalization, and install flag reconstruction for git/path sources.
Library/Homebrew/test/bundle/cargo_spec.rb Adds specs for entry validation, checking behavior, dumping behavior, and install argument construction with source:.
docs/Brew-Bundle-and-Brewfile.md Documents cargo ... source: usage and how dump/restore handles git selectors and commit stripping.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread docs/Brew-Bundle-and-Brewfile.md Outdated
Comment thread Library/Homebrew/test/bundle/cargo_spec.rb
Comment thread Library/Homebrew/bundle/extensions/cargo.rb
tftio and others added 2 commits August 5, 2026 14:15
Two forms were accepted at parse time that `cargo install` cannot act
on, so the failure surfaced later and less clearly.

`--git` takes a URL and rejects an scp-style remote outright, naming
the `ssh://` form to use instead, so require a scheme rather than also
accepting anything ending in `.git`.

Only a `branch`, `tag` or `rev` query is restored as a `cargo install`
flag. Any other query was accepted and then silently dropped, which
left the installed origin unequal to the `Brewfile` entry and so made
`brew bundle check` report the crate missing on every run.

@MikeMcQuaid MikeMcQuaid left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for PR! One high-level comment before more detailed review.

Comment thread docs/Brew-Bundle-and-Brewfile.md Outdated
Neither a local path nor a file:// URL resolves on another machine, so
both are rejected when the Brewfile is parsed. A crate cargo reports as
installed from one is dumped as a registry crate rather than dropped,
with a warning naming the origin that could not be expressed.
@tftio

tftio commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

Heads up -- the scope of this PR has narrowed since I opened it, and the description above is now out of date in a few places. I have left it as written so the review threads still read in order.

What changed, per @MikeMcQuaid’s review:

  1. Local paths are no longer accepted as a cargo source:, and neither are file:// URLs. A source: is now a git URL with an ssh://, git:// or https:// scheme, and anything else is rejected when the Brewfile is parsed.

  2. A crate that cargo install --list reports as installed from a local origin is dumped as an ordinary registry entry rather than dropped, with a warning naming the origin that could not be expressed. Dropping it silently would recreate the incomplete-Brewfile problem this PR exists to fix.

The bits of the PR that show the path example, then, are no longer valid. I chose not to rewrite the PR, but rather to call it out here, to keep the provenance clean.

@MikeMcQuaid MikeMcQuaid left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks! Could you open another draft PR for the related uv local change?

Comment thread Library/Homebrew/bundle/extensions/cargo.rb Outdated
A crate cargo reports as installed from a local origin is still dumped
as a registry crate, but without warning about the origin that could
not be expressed, which is noise for anyone who is content with the
crate they have.
@tftio

tftio commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Thanks! Could you open another draft PR for the related uv local change?

yep:

#23469

@MikeMcQuaid MikeMcQuaid left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks! Looks good when CI is 🟢

@tftio

tftio commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Thanks! Looks good when CI is 🟢

Thanks! This was a very easy process, appreciate your patience.

@MikeMcQuaid
MikeMcQuaid added this pull request to the merge queue Aug 7, 2026
Merged via the queue into Homebrew:main with commit 136ad7e Aug 7, 2026
64 of 65 checks passed
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.

3 participants