rust-lang / rust-lang/cargo

`cargo update -p bar` where `bar` is patched can partially unpatch `bar`

Open
#8,355 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-dependency-resolution A-patch C-bug Command-update S-needs-design
Dominant language
Rust
Stars
15.5k
Forks
3k
Avg merge
23h 30m
Merged PRs (30d)
51

Description

Problem
If there is a [patch] for something at version 0.1.0, and you need to update the [patch] to version 0.1.1, but there is also a 0.1.2 available in the registry, cargo update is too aggressive and will pick 0.1.2. This can lead to a somewhat corrupt state where there are two different semver compatible versions in the lockfile.

See https://github.com/rust-lang/rust/pull/73238#issuecomment-643060741 for a real-life example.

Note: This isn't specific to cargo update. Implicit updates from cargo build also cause this.

Steps
Repro as a cargo test:

#[cargo_test]
fn update_patch_when_newer_available() {
    // `cargo update` when there is a patch, and there is a *newer*
    // version available on crates.io.
    Package::new("bar", "0.1.0").publish();

    let p = project()
        .file(
            "Cargo.toml",
            r#"
                [workspace]
                members = ["foo", "bar"]

                [patch.crates-io]
                bar = { path = "bar" }
            "#,
        )
        .file(
            "foo/Cargo.toml",
            r#"
                [package]
                name = "foo"
                version = "0.1.0"

                [dependencies]
                bar = "0.1"
            "#,
        )
        .file("foo/src/lib.rs", "")
        .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
        .file("bar/src/lib.rs", "")
        .build();

    // Establish an initial Cargo.lock.
    p.cargo("tree")
        .with_stdout(
            "\
bar v0.1.0 ([ROOT]/foo/bar)

foo v0.1.0 ([ROOT]/foo/foo)
└── bar v0.1.0 ([ROOT]/foo/bar)
",
        )
        .run();

    Package::new("bar", "0.1.1").publish();
    Package::new("bar", "0.1.2").publish();

    p.change_file("bar/Cargo.toml", &basic_manifest("bar", "0.1.1"));

    // Ideally this would just work, and pick 0.1.1 from the workspace.
    // Unfortunately it picks 0.1.2.
    // p.cargo("update -p bar").run();
    // This doesn't work either (it picks 0.1.2).
    // p.cargo("update -p bar --precise 0.1.1").run();

    // Currently, the only solution is to do:
    //  cargo update -p bar
    //  cargo update -p bar:0.1.2 --precise 0.1.1
    // 
    // where the second command downgrades and reverses the damage from the first command.
}

Notes

cargo 1.45.0-nightly (40ebd5220 2020-06-01)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by running the supplied cargo test case, update_patch_when_newer_available, and inspect how cargo update and implicit cargo build resolution handle the [patch] entry. Done means the patched workspace version 0.1.1 is selected without introducing the newer registry version 0.1.2 or duplicate compatible versions in Cargo.lock.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
build-system
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.