Description
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 (like1.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
- cargo install --reinstall? #2082 — Issue about upgrade support.
cargo install
should check if binary isn't installed/outdated before downloading crate and it shouldn't fail otherwise #6485 — Another upgrade issue- Add ensure option to cargo install #6595 (comment) — proposal to add upgrade
- https://crates.io/crates/cargo-update
- https://crates.io/crates/cargo-ensure-installed
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 ofwhich 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