Repository navigation
Fix Cargo member globs with [..] classes (#1833) - #1866
Mikola Lysenko (mikolalysenko) wants to merge 4 commits into
Conversation
Assisted-by: Claude Code:claude-opus-5-5
A workspace whose members list uses a character class, such as members = ["crates/[ab]*"], expanded to no members: the member walk's own matcher read only * and ?, while cargo's glob crate also reads [abc], [a-z] and [!x]. Vendored Cargo, the upstream Cargo redirect and hosted Cargo then never saw those crates. Match each glob segment through workspace_globs::segment_glob_matches, the matcher the npm-family walks already use, and drop the copy. Fixes #1833 Assisted-by: Claude Code:claude-opus-5-5
Cargo's glob crate negates a class only on `!`, so members = ["crates/[^x]*"] names crates starting with `^` or `x`; the shared matcher read it as negated and picked the opposite crates. A `^` opening a class is now kept as a member. A segment counts as a glob only when it has `*`, `?` or a class that closes, so an unclosed `[` stays a literal directory, and the lockless Cargo redirect refusal now names `crates/[ab]` as a members pattern instead of a missing member, matching the member walk. Refs #1833 Assisted-by: Claude Code:claude-opus-5-5
|
BugBot review Generated by Claude Code |
|
Burn-down agent: labeled Ready for review at
Generated by Claude Code |
Final review brief:
|
A members entry like x[^] is a class matching `^` to cargo's glob crate, which negates only on `!`. The pattern check treated the `^` as a negation and read the entry as a literal directory instead. Refs #1833 Assisted-by: Claude Code:claude-opus-5-5
|
[agent] Fixed the review brief's open question in d177158: Generated by Claude Code |
|
BugBot review Generated by Claude Code |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit d177158. Configure here.
Final review brief:
|
LLM Description written by Claude Code:claude-opus-5-5
Fixes #1833
Summary
A Cargo workspace whose
memberslist uses a character class, such asmembers = ["crates/[ab]*"], expanded to no members. Vendored Cargo,the upstream Cargo redirect and hosted Cargo (disk and in-memory) all read
members through
cargo_workspace::member_manifests*, so they never sawthose crates.
Root cause
utils/cargo_workspace.rsmatched each glob segment with its ownwildcard_match, which read only*and?and treated[as aliteral. Cargo expands members with the
globcrate, which also reads[abc],[a-z]and[!x].Change
expand_frommatches segments throughworkspace_globs::segment_glob_matches(the npm-family matcher), andwildcard_matchis deleted.globcrate negates only on!, so[^x]is the class of^and
x. The shared matcher also negates on^, so the cargo walkputs a NUL member (which no directory name can hold) ahead of a
^that opens a class.
is_member_pattern: a segment is a glob when it has*,?or a[..]class that closes. The member walk and the lockless Cargoredirect refusal (
cargo_lockless_other_dependencies) both use it, sothe refusal names
crates/[ab]as a members pattern, not a missingliteral member. An unclosed
[stays on the literal path as before.Tests (red → green)
cargo_workspace::tests::member_globs_read_character_classes([ab]*,[a-b]?*,[!a]*,[^x]*)libs/*hits)cargo_workspace::tests::a_bracket_class_matches_a_literal_bracket(x[[]?)cargo_workspace::tests::member_patterns_are_wildcards_or_closed_classesredirect::testslockless refusal namescrates/[ab]as a patternCommands run locally:
cargo fmt --all -- --check: cleancargo clippy --workspace --all-features -- -D warnings: cleancargo test -p socket-patch-core --all-features: 6996 passed, 4 failed. The 4 (copy_tree::relax_loop_must_not_traverse_symlinked_root,vlt_heal::an_unremovable_hidden_lock_keeps_every_store_entry,pypi_poetry::wire_write_failure_maps_error_and_leaves_lock_untouched,pypi_requirements::wire_failure_rolls_back_already_written_files) depend onchmod 0555blocking writes, which it doesn't for root (this sandbox runs as uid 0). They don't touch Cargo code.cargo test -p socket-patch-cli --all-features --test e2e_cargo --test e2e_redirect_cargo_shapes --test e2e_vendor_cargo_build --test e2e_redirect_cargo_build -- --include-ignored: 25 + 35 + 40 + 23 passedcargo test --workspacedidn't fit in this sandbox's disk allowance (it ran out of space linking every CLI test binary), so CI'stestjob covers the rest.No wrapper changes:
npm/,pypi/andgem/don't read Cargo workspaces./code-review highfindings not fixed hereThese all predate this PR. Each rule already applied to
*and?;the PR only extends it to classes:
excludeis globbed. Cargo readsexcludeas literal pathprefixes, but
member_manifests_withalready globbed it with*.Making it prefix-based changes
*excludes too, so that belongs in itsown issue.
but cargo's
glob()usesrequire_literal_leading_dot: false. Thisrule is older than this PR, and
*already followed it.segment_glob_matchesbacktracks with no memo,and so did the deleted
wildcard_match. This PR doesn't change thecost.
[. Cargo refuses an unclosed[(could not parse pattern). Here it stays a literal path, as it was on main, and no newtest locks that in.
Picked over the p1 refactors #1844 and #1839 because both would rewrite
files that open PRs #1865 and #1855 are changing. #1862 (p2) builds on
go_build_list.rs, which open PR #1843 rewrites.https://claude.ai/code/session_011f9aeSAqJp6HmcFwxb9HL5
Generated by Claude Code