Repository navigation
Give back a Cargo config with no final newline on hosted remove - #2078
Mikola Lysenko (mikolalysenko) wants to merge 3 commits into
Conversation
Hosted `scan` then `remove` left a newline at the end of a `.cargo/config.toml` that had none. The rewriter appended two newlines before its `[registries.socket-patch-<uuid>]` block there: one to end the user's last line, one as a blank separator. `remove` takes back the block and one newline. The edit record carried the extra newline for the ledger-based revert older CLIs had; v5 hosted mode keeps no ledger, and the file itself cannot tell that config from one that ended in a newline, so the extra one stayed. The rewriter now puts exactly one newline before the block whatever the config ends with. After a final newline that is the blank separator, as before. After none it is the line ending the config lacked, and the block follows the last line directly. remove_registry_block already inverts that form byte for byte and is unchanged. A config that 5.1.0 or earlier already hosted still comes back with the final newline added: nothing in the file says which form it had. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
e2e_redirect_cargo_shapes let a file with no final newline come back with one added, because the rewriter could not help it. With one newline before the appended registry block the restore is exact, so the check now compares every file byte for byte. cargo_hosted_config_trailing_bytes_are_restored covers the `config-unterminated` shape with real cargo. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
From /code-review high on the PR. With the block straight after a config's last line, content the user later put directly after the block was glued to that line on `remove` (`retry = 3[build]`), which cargo cannot parse. That was new with the previous commit. The newline before the block now stays when taking it would join two lines. Three older defects in the same function are fixed with it: - A config with mixed line endings came back all CRLF. Only a file whose every line ends in CRLF is converted, the rewriter's own rule. - A comment heading the next section was deleted with the block. Blank lines and comments after the block's last key are the user's and stay. - The block was found by searching for its text, which could match inside another line. It is located by its header line. remove_appended_cargo_block is folded into remove_registry_block; its CRLF branches were unreachable from there. A new golden, redirect/cargo/cargo/config-unterminated, pins the append for a config with no final newline in the rewrite, restore and vex discovery goldens. restore_gives_back_a_config_with_no_final_newline takes its hosted bytes from the rewriter, so it no longer passes without the fix. Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
PR SummaryMedium Risk Overview
E2E Reviewed by Cursor Bugbot for commit 2c6cb5d. Configure here. |
|
[agent] PR shepherd: review brief for the approver What it does. Hosted Risk. Low-medium. Only hosted Cargo config files change. In a config with no final newline the block now follows the last line directly, with no blank line in between (still valid TOML). Configs hosted by an earlier release still get a final newline added on Look here.
Verified. I read the whole diff and traced the byte arithmetic in Changes I made. None. Open questions. None blocking. A cross-repo follow-up: depscan's TypeScript rewriter has the same two-newline append, so its parity test will fail on the next socket-patch bump unless it follows or the case goes in Generated by Claude Code |
Problem
Hosted
scanfollowed byremovedid not give back a.cargo/config.tomlthat had no final newline. The config came back with a newline added:The rewriter appended two newlines before its
[registries.…]block in that case: one to end the user's last line and one as a blank separator.removetakes back the block and one newline. The edit record carried the extra newline for the ledger-based revert older CLIs had. v5 hosted mode keeps no ledger, and nothing in the file tells this config apart from one that ended in a newline, so the extra newline stayed.e2e_redirect_cargo_shapesknew about this and tolerated it.Fix
The rewriter now puts exactly one newline before the block whatever the config ends with. After a final newline that is the blank separator, as before. After none it is the line ending the config lacked, and the block follows the last line directly:
That is valid TOML, and taking back the block plus one newline gives the original bytes in both cases.
The cost is the blank line before the block in a config with no final newline. I chose exact restore over that blank line because
removehas no other way to know what the file ended with.Review
/code-review highreported eight findings. Seven are fixed here, andremove_registry_blockwas rewritten for them (it now locates the block by line, andremove_appended_cargo_blockis folded into it):remove(retry = 3[build]), which cargo cannot parse. The newline before the block now stays when taking it would join two lines.tests/fixtures/redirect/cargo/cargo/config-unterminated, which the rewrite golden, the restore round-trip golden and the vex discovery golden all run.restore_gives_back_a_config_with_no_final_newlinenow takes its hosted bytes from the rewriter.Not fixed:
remove. With nothing but whitespace left, the file can't be told apart from one the rewriter created and an editor later touched, and deleting a config that holds nothing is the existing cleanup rule. Older than this PR.Follow-up for depscan
depscan's TypeScript rewriter (
workspaces/app/src/patches/registry-rewrite/cargo.ts) has the same two-newline append. With the new golden, its parity test will fail on depscan's next socket-patch bump until the rewriter follows or the case is listed inTS_LAGGING.Testing
cargo_config_append_is_undone_byte_for_byte: the rewriter's append and the removal over six configs (final newline, none, trailing blank lines, comment only, CRLF with and without a final newline), then two patches appended to an unterminated config and removed in either order.content_after_the_block_is_keptandmixed_line_endings_are_left_as_they_arecover the review findings.e2e_redirect_cargo_shapesno longer tolerates an added final newline. Itsconfig-unterminatedshape passes with real cargo 1.93.1.cargo test -p socket-patch-core --lib: 7,741 passed. The rewrite and restore goldens pass with the new fixture, as do the hosted Cargo CLI suites (e2e_redirect_cargo_shapes,e2e_redirect_cargo_build,in_process_redirect,hosted_memory_engine,mode_migration_cargo,e2e_vex_redirect).cargo fmt --checkandcargo clippy --locked --workspace --all-features -- -D warningsare clean.rollback_byte_identicalcheck found this on the hostedconfig-unterminatedcell, passes that cell with this branch.🤖 Generated with Claude Code