Skip to content

Proposal: cargo install with upgrades #6667

Closed
@ehuss

Description

@ehuss

This is a proposal to change the behavior of cargo install as discussed at #6595 (comment):

cargo install will be changed to reinstall an already installed package if it is not "up to date" instead of failing.

The determination of "up to date" is defined as follows:

  • If --version is specified with an exact version (like 1.2.3), the installed version must be exactly the given version.
  • If --version is specified with a version requirement (like ~1.2.3), it checks the registry for the greatest version matching the requirement (not including pre-release versions), and ensures the installed version is exactly that version.
  • If --git is specified, the installed git hash must match exactly.
  • If --path is specified, it is always reinstalled.
  • If none of the flags above are given (such as cargo install foo), then it is treated as --version=*.
  • The package will be reinstalled if the settings are not the same. The settings includes:
    • Enabled features
    • --debug
    • The set of binaries is different (such as using different target selectors --bin, --bins, --example, --examples)
    • --target
    • The source

Additional clarifications:

  • Fundamentally, the only change in behavior is when cargo install currently fails.
  • Installation will still fail if installation would create a binary of the same name that already exists in another package (of a different name).
  • If the package is up to date, the command exits with success (0).
  • --force continues to force an install, even if it appears up to date.
  • A report at the end should clearly indicate which packages were upgraded and which were skipped.
  • Updates in dependencies do not trigger an update.
  • This will be implemented behind an unstable flag.

.crates.toml Changes

More metadata will need to be stored. Currently it only tracks a mapping of PackageId to the set of binaries it installs. I see two ways to approach migrating to a new format:
1. Switch .crates.toml to V2. This will cause older versions of Cargo to fail to install.
2. Use a new filename (.crates2.json). This will allow older and newer Cargos to coexist.
I lean towards the second option, since it would cause less friction, with minimal drawbacks. Additionally, the new file could be designed with forwards compatibility in mind. Specifically, unknown fields for untouched packages should be preserved.

I lean towards changing the format to json. This file is not intended to be user-edited, and toml can be finicky sometimes.

Here's a commented description of the new file format:

{
    "packages": {
        "pkg_name": {
            // Version number of the package.
            "version": "1.0.0",
            // The version requested on the command-line with `--version`.
            // Not specified if `--version` was not used.
            "version_req": "1.0",
            // The source URL.
            "source": "source_url",
            // The list of binary names installed.
            "bins": ["foo", "foo2"],
            // List of features enabled.
            "features": ["default", "featname"],
            // Either "debug" or "release".
            "profile": "release",
            // The installation target.
            // Either the host or the value specified in `--target`.
            "target": "x86_64-apple-darwin",
            // Output of `rustc -V`.
            "rustc": "rustc 1.32.0 (9fda7c223 2019-01-16)",
        }
    }
}

It should continue to keep .crates.toml up-to-date with its original format.

References

Update all

I think it might be desirable to have the ability to update all outdated packages. I propose this should be decided upon separately, and should be implemented separately afterwards if it is desired. I think it is desirable to avoid too much complication in one command, so care should be taken. If it can be done with a single flag, that might be acceptable.

One possibility is to have an --outdated flag to perform this task. By default, it should update all outdated packages installed from a registry. There are various details to be decided on:

  • Should there be a confirmation before starting?
  • Should there be a way to see which packages will be updated (--dry-run? --outdated --list?)?
  • Should it support git packages? Perhaps --outdated could take some optional arguments, such as --outdated=git.
  • Should there be a way to upgrade based on toolchain? Perhaps --outdated=toolchain?
  • This command could have bad interaction with packages installed with features or other settings. Should those settings be sticky (and only version is updated?)? What if a package was installed with an explicit --version?

Questions

  • How should a change in rustc toolchain be handled? My preference is that it should be ignored. For the majority of cases, it doesn't have a significant impact.
  • Should there be an option to disable upgrades (à la apt-get --no-upgrade). My preference is "no" (just to reduce the number of flags), but I am not opposed. There is a workaround of which foo || cargo install foo.
  • Should other environment/config items that affect compilation be tracked? I lean towards "no". Possible items:
    • RUSTC, RUSTC_WRAPPER, RUSTFLAGS, CARGO_INCREMENTAL
    • [target] settings (rustflags, linker, ar)
    • [build] settings (rustc, rustflags, incremental)
    • Config-profiles

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions