fix(sdist): regenerate Cargo.lock when workspace members are removed#3192
Open
ckhordiasma wants to merge 2 commits into
Open
fix(sdist): regenerate Cargo.lock when workspace members are removed#3192ckhordiasma wants to merge 2 commits into
ckhordiasma wants to merge 2 commits into
Conversation
Fixes PyO3#2609. When maturin builds an sdist from a workspace, `rewrite_cargo_toml` strips workspace members not needed by the package. The Cargo.lock was copied verbatim and still referenced those removed crates, so `cargo build --locked` inside the sdist would fail. After all sdist entries are assembled, materialize them to a temp directory, run `cargo generate-lockfile` to reconcile the lockfile, and replace the tracker entry with the regenerated Cargo.lock. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Exercises the fix for PyO3#2609: builds an sdist from a workspace member while a sibling member (`devtool`, with a unique `rand` dependency) is stripped, then asserts `cargo metadata --frozen` succeeds in the unpacked sdist. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes sdists produced from Cargo workspaces where rewrite_cargo_toml removes unneeded workspace members but the copied Cargo.lock still references them, causing cargo build --locked / cargo metadata --frozen to fail inside the unpacked sdist.
Changes:
- Add
VirtualWriter<SDistWriter>::materialize_toandreplace_byteshelpers to support post-processing tracked sdist entries. - After assembling workspace-related sdist entries, materialize the sdist to a temp dir, run
cargo generate-lockfile, and replace the sdist’sCargo.lockwith the regenerated version. - Add a regression test that constructs a two-member workspace, builds an sdist for one member, unpacks it, and asserts
cargo metadata --frozensucceeds.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
tests/run/sdist.rs |
Adds regression coverage ensuring workspace-member sdists have a usable Cargo.lock. |
src/source_distribution/mod.rs |
Adds regenerate_cargo_lock step in the sdist build pipeline to reconcile lockfiles after workspace-member stripping. |
src/module_writer/virtual_writer.rs |
Adds helpers to materialize tracked sdist entries to disk and replace a tracked file’s bytes in-memory. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+750
to
+757
| let logical_manifest_dir = ctx | ||
| .project | ||
| .manifest_path | ||
| .parent() | ||
| .map(Path::to_path_buf) | ||
| .unwrap_or_else(|| ctx.abs_manifest_dir.clone()); | ||
| let is_in_workspace = ctx.workspace_root.as_std_path() != logical_manifest_dir; | ||
| if !is_in_workspace { |
| ArchiveSource::File(f) => { | ||
| fs_err::copy(&f.path, &dest)?; | ||
| } | ||
| } |
Comment on lines
+566
to
+582
| /// Write all tracked entries to a directory on disk. | ||
| pub(crate) fn materialize_to(&self, dir: &Path) -> Result<()> { | ||
| for (target, source) in &self.tracker { | ||
| let dest = dir.join(target); | ||
| if let Some(parent) = dest.parent() { | ||
| fs_err::create_dir_all(parent)?; | ||
| } | ||
| match source { | ||
| ArchiveSource::Generated(g) => { | ||
| fs_err::write(&dest, &g.data)?; | ||
| } | ||
| ArchiveSource::File(f) => { | ||
| fs_err::copy(&f.path, &dest)?; | ||
| } | ||
| } | ||
| } | ||
| Ok(()) |
Comment on lines
+586
to
+594
| pub(crate) fn replace_bytes(&mut self, target: &Path, data: Vec<u8>) { | ||
| self.tracker.insert( | ||
| target.to_path_buf(), | ||
| ArchiveSource::Generated(GeneratedSourceData { | ||
| data, | ||
| path: None, | ||
| executable: false, | ||
| }), | ||
| ); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #2609.
When maturin builds an sdist from a workspace,
rewrite_cargo_tomlstrips workspace membersnot needed by the package. The
Cargo.lockwas copied verbatim and still referenced thoseremoved crates, so
cargo build --lockedinside the sdist would fail.After all sdist entries are assembled in the virtual writer, materialize them to a temp
directory, run
cargo generate-lockfileto reconcile the lockfile, and replace the trackerentry with the regenerated
Cargo.lock. This only runs for workspace crates that have aCargo.lockentry in the sdist.Changes
materialize_toandreplace_byteshelpers onVirtualWriter<SDistWriter>regenerate_cargo_lockstep afteradd_workspace_manifestin the sdist buildera unique dependency), unpacks it, and asserts
cargo metadata --frozensucceedsTest plan
cargo test --test run -- sdist_workspace_removed_members_cargo_lockpasses with the fixmainwithout the fix (verified on a separate branch)cargo fmtandcargo clippyclean🤖 Generated with Claude Code — ~40 back-and-forth messages covering issue analysis, implementation, line-by-line code walkthrough, test authoring, failure verification, style review, and PR creation.