Skip to content

fix: --age の検査で更新を取りやめるとき、Cargo.lock も Cargo.toml と一緒に戻す - #60

Merged
owayo merged 2 commits into
mainfrom
fix/issue-58-restore-cargo-lock-with-manifest
Oct 23, 2026
Merged

owayo merged 2 commits into
mainfrom
fix/issue-58-restore-cargo-lock-with-manifest

Conversation

@owayo

@owayo owayo commented Oct 23, 2026

Copy link
Copy Markdown
Owner

概要

--install で更新を取りやめるとき、Cargo.toml だけが実行前に戻り、Cargo.lock は「File changed outside a package-manager command」として残ることがありました (#58)。2 つが食い違ったまま終わるので、cargo ... --locked が通らなくなります。この PR で、Cargo.lock も一緒に戻すようにします。あわせて、どうしても戻せないファイルがあるときに、一部だけ戻して食い違いを作らないようにします。

原因

監査は、若い版を cargo update -p <crate>@<ver> --precise <older> で差し戻します。cargo はこのとき、差し戻す crate と、前の lock でそこから依存をたどれる crate を lock から外します。差し戻しと無関係な crate (依存元) でも、それらを指す辺は、版要求の許す同じ名前の別の版へ付け替わります。windows-sys >=0.52, <0.62 のように系列をまたぐ要求なら、付け替え先は別の系列になります。

depup は、依存元の辺の付け替えを「この操作で動いた版から、同じ semver 系列の版へ」の場合しか cargo 自身の変更と認めていませんでした。それ以外は外部変更として記録し、監査は Cargo.lock の受領書を出しません。install の復元は、受領書の無い Cargo.lock を「depup の外で変わった」とみなして上書きせず、Cargo.toml だけを戻していました。

実際のプロジェクトの写しで、git の依存の tag を上げると zstd 0.14.3 が入る状況を再現しました。tokio と ureq の差し戻しで、errno・tempfile・dirs-sys などの windows-sys / getrandom / base64 への辺が別の系列へ付け替わりました。その結果、10 件の依存元が外部変更と記録されていました。

変更内容

  • 単一 crate の差し戻し (AuditChanges::applied): 消えた辺が cargo の外した集合 (差し戻した crate と、前の lock でそこから到達できる crate。取得元込みで辿る) を指し、追加された辺が同じ名前・取得元なら、その付け替えを cargo 自身の変更とします。版と系列は問いません。辺の数やほかのフィールドが変わった場合と、外していない集合を指していた辺の付け替えは、従来どおり外部変更です。
  • 一時ワークスペースで解いて書き戻す操作 (まとめ解きと、部分的な差し戻しの取り消し): 新設の AuditChanges::committed で記録し、選んだ範囲の外の変化を外部変更にしません。反映の直前に元の lock が変わっていないことを確かめているので、差分はすべて depup のものです。固定用の依存が lock に無い版を指すと、cargo は crates.io のパッケージをすべて lock から外して解き直すため、無関係な依存元の辺も付け替わります (テストで確認)。
  • 復元 (InstallTransactions::rollback): lock の検証の失敗では、単位に 1 つでも戻せないファイルがあれば、どのファイルも戻しません。変更のあるファイルの復旧用コピーを残し、「Recovery was skipped」と報告します。JSON の失敗理由の末尾は recovery incomplete: a file changed outside depup, so no file of this install was restored and all were kept for manual recovery です。install の失敗では従来どおり戻せるファイルは戻し、残したファイルが戻したファイルと合わない可能性を最後に示します。
  • docs/usage.md・docs/usage.ja.md・AGENTS.md を更新しました。

設計判断

codex (gpt-6.1-sol) に設計と差分を相談しました。

  • 付け替えを認める条件は、cargo の update -p が lock から外す集合 (register_previous_locks の avoid_locking) に合わせました。依存元の版要求を crates.io から読んで確かめる案は、要求を満たすことが cargo の書き込みの証拠にならないため採りませんでした。
  • 戻せないファイルがあるときの扱いは、復元の理由で分けました。codex は理由で分けない案を勧めましたが、install の失敗ではパッケージマネージャーが lock を書いていないことが多く、整合しているのは実行前の組です。lock の検証の失敗では、パッケージマネージャーが成功して書いた組が整合しています。どちらでも、整合している組を崩さない側を選びました。
  • 差分レビューの指摘 2 件を直しました。lock から外した集合を名前と版だけで作ると、同じ名前・版の別の取得元まで含めてしまう点と、復元を見送ったときの案内が、コピーを作れなかったファイルにも「コピーから戻す」と読める点です。

部分的な差し戻しを install 直後の版へ戻すときの検査 (check_restoration の same_edges) も、同じ系列の付け替えしか認めていません。こちらが誤って止まっても、install 直後の lock 全体への復元に切り替わるだけで、install 単位の復元の結果は変わりません。そのため、この PR では変えていません。

検証

  • make ci (fmt・clippy・全テスト): pass。1 つ目のコミット単独でも、install と監査のテスト 232 件が通ることを確かめました
  • 実際のプロジェクトの写しでの再現: 修正前は Cargo.toml だけが戻り、修正後は Cargo.toml と Cargo.lock の両方が実行前のバイト列に戻りました
  • 偽 crates.io と実物の cargo による回帰テスト: 単一の差し戻しで依存元の辺が別の系列へ付け替わっても受領書を出す / 通しの install で Cargo.toml と Cargo.lock が実行前に戻る (この 2 件は修正前に失敗することを確認) / まとめ解きで無関係な依存元の辺が付け替わっても外部変更にしない (修正前の記録の仕方では外部変更になることを実験で確認)。どのテストも、cargo が実際に付け替えたことを先に確かめています
  • 単体テスト: 付け替えの判定 (系列をまたぐ付け替え・外していない集合への付け替え・別の取得元・辺の増減)、committed が以前の記録を残すこと、lock の検証の失敗では lockfile とマニフェストのどちらが外部で変わっても単位のどのファイルも戻さないこと、install の失敗では戻せるファイルを戻すこと

Closes #58

🤖 Generated with Claude Code

owayo and others added 2 commits October 23, 2026 10:07
Cargo.lock の --age 監査は、`cargo update -p <crate>@<ver> --precise` の前後で変わった
パッケージのうち、差し戻した範囲の外のものを外部変更として記録していた。外部変更が
1 件でもあると受領書を出さないので、install の復元では Cargo.lock が「File changed
outside a package-manager command」として残り、Cargo.toml だけが戻っていた (#58)。

`cargo update -p X` は X と、前の lock で X から到達できるパッケージを lock から外す。
範囲外の依存元でも、それらを指す辺は版要求の許す同じ名前の別の版へ付け替わり、
`windows-sys >=0.52, <0.62` のような系列をまたぐ要求では別の系列になる。実プロジェクトでは
tokio と ureq の差し戻しで、errno や tempfile などの windows-sys / getrandom / base64 の辺が
付け替わっていた。依存元の付け替えは、消えた辺が lock から外した集合 (取得元込みで辿る) を
指し、追加された辺が同じ名前・取得元なら、Cargo 自身の変更とする。

一時ワークスペースで解いて書き戻す操作 (まとめ解きと restore_mixed) は、反映の直前に
元の lock が変わっていないことを確かめているので、差分はすべて depup のもの。固定用の
依存が lock に無い版を指すと、Cargo は crates.io のパッケージをすべて lock から外すため、
無関係な依存元の辺も付け替わる。AuditChanges::committed で記録し、範囲外の変化を
外部変更にしない。

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
外部の変更で戻せないファイルがあると、ほかのファイルだけを実行前へ戻していた。lock の
検証の失敗ではパッケージマネージャーが成功しているので、マニフェストだけを戻すと、残した
Cargo.lock と食い違い、`cargo --locked` が通らなくなる (#58)。

lock の検証の失敗では、単位に 1 つでも戻せないファイルがあれば、どのファイルも戻さずに
復旧用コピーを残し、復元を見送ったことを報告する。install の失敗では実行前の組が合って
いるので、従来どおり戻せるファイルは戻し、残したファイルが戻したファイルと合わない
可能性を最後に示す。

文書と AGENTS.md に、依存元の付け替えの扱い (前のコミット) と復元の扱いを書く。

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@owayo owayo self-assigned this Oct 23, 2026
@coderabbitai

coderabbitai Bot commented Oct 23, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 79875627-aad5-4f70-8952-b1cc22c73801
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@owayo
owayo merged commit 3ddf362 into main Oct 23, 2026
8 checks passed
@owayo
owayo deleted the fix/issue-58-restore-cargo-lock-with-manifest branch October 23, 2026 01:21
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.

更新が --age の検査で失敗したとき、Cargo.toml だけを戻して Cargo.lock を戻さず、食い違ったまま終わる

1 participant