Skip to content

Commit fb44150

Browse files
committed
Auto merge of #7560 - ehuss:stabilize-install-upgrade, r=alexcrichton
Stabilize install-upgrade. Tracking issue: #6797 This stabilizes the install-upgrade feature, which causes `cargo install` to reinstall a package if it appears to be out of date, or exit cleanly if it is up-to-date. There are no changes from `-Zinstall-upgrade`. See [the old unstable docs](https://github.com/rust-lang/cargo/blob/6a7f505a185b000e38bdad64392098e0b2e50802/src/doc/src/reference/unstable.md#install-upgrade) for a refresher on the details of what it does. This also stabilizes the following changes: - `--version` no longer allows an implicit version requirement like `1.2`. It must be either contain all 3 components (like `1.2.3`) or use a requirement operator (like `^1.2`). This has been a warning for a very long time, and is now changed to a hard error. - Added `--no-track` to disable install tracking. **Motivation** I just personally prefer this behavior, and it has been requested a few times in the past. I've been using it locally, and haven't run into any issues. If this goes into 1.41, then it will release on Jan 30, about 10 months since it was added in #6798. **Concerns** Regarding some of the concerns I had: - Is it tracking the correct set of information? I'm satisfied with the current set. It also tracks, but does not use, the version of rustc and the version specified in the `--version` flag, in case we ever want to use that in the future. It is also designed to be backwards and forwards compatible, so more information can be added in the future. I think the current set strikes a good balance of tracking the really important things, without causing unnecessary rebuilds. - Method to upgrade all outdated packages? This can always be added as a new flag or command in the future, and shouldn't block stabilization. - Should `--no-track` be kept? Does it work correctly? I kept it. It's not too hard to support, and nobody said anything (other than maybe using a less confusing name). - Should this be the default? Should there be a way to use the old behavior? I like it as the default, and don't see a real need for the old behavior. I think we could always bring back the old behavior with a flag in the future, but I would like to avoid it for simplicity. There is also the workaround of `which foo || cargo install foo`. Closes #6797. Closes #6727. Closes #6485. Closes #2082.
2 parents dba478b + f7b2971 commit fb44150

File tree

11 files changed

+323
-379
lines changed

11 files changed

+323
-379
lines changed

src/bin/cargo/cli.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ Available unstable (nightly-only) flags:
3434
-Z no-index-update -- Do not update the registry, avoids a network request for benchmarking
3535
-Z unstable-options -- Allow the usage of unstable options such as --registry
3636
-Z config-profile -- Read profiles from .cargo/config files
37-
-Z install-upgrade -- `cargo install` will upgrade instead of failing
3837
-Z timings -- Display concurrency information
3938
-Z doctest-xcompile -- Compile and run doctests for non-host target using runner config
4039

src/bin/cargo/commands/install.rs

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,7 @@ pub fn cli() -> App {
4646
))
4747
.arg_jobs()
4848
.arg(opt("force", "Force overwriting existing crates or binaries").short("f"))
49-
.arg(opt(
50-
"no-track",
51-
"Do not save tracking information (unstable)",
52-
))
49+
.arg(opt("no-track", "Do not save tracking information"))
5350
.arg_features()
5451
.arg_profile("Install artifacts with the specified profile")
5552
.arg(opt("debug", "Build in debug mode instead of release mode"))
@@ -90,13 +87,9 @@ crate has multiple binaries, the `--bin` argument can selectively install only
9087
one of them, and if you'd rather install examples the `--example` argument can
9188
be used as well.
9289
93-
By default cargo will refuse to overwrite existing binaries. The `--force` flag
94-
enables overwriting existing binaries. Thus you can reinstall a crate with
95-
`cargo install --force <crate>`.
96-
97-
Omitting the <crate> specification entirely will install the crate in the
98-
current directory. This behaviour is deprecated, and it no longer works in the
99-
Rust 2018 edition. Use the more explicit `install --path .` instead.
90+
If the package is already installed, Cargo will reinstall it if the installed
91+
version does not appear to be up-to-date. Installing with `--path` will always
92+
build and install, unless there are conflicting binaries from another package.
10093
10194
If the source is crates.io or `--git` then by default the crate will be built
10295
in a temporary target directory. To avoid this, the target directory can be
@@ -159,13 +152,6 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
159152
let version = args.value_of("version");
160153
let root = args.value_of("root");
161154

162-
if args.is_present("no-track") && !config.cli_unstable().install_upgrade {
163-
return Err(failure::format_err!(
164-
"`--no-track` flag is unstable, pass `-Z install-upgrade` to enable it"
165-
)
166-
.into());
167-
};
168-
169155
if args.is_present("list") {
170156
ops::install_list(root, config)?;
171157
} else {

src/cargo/core/features.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,6 @@ pub struct CliUnstable {
334334
pub config_profile: bool,
335335
pub dual_proc_macros: bool,
336336
pub mtime_on_use: bool,
337-
pub install_upgrade: bool,
338337
pub named_profiles: bool,
339338
pub binary_dep_depinfo: bool,
340339
pub build_std: Option<Vec<String>>,
@@ -400,7 +399,6 @@ impl CliUnstable {
400399
"dual-proc-macros" => self.dual_proc_macros = parse_empty(k, v)?,
401400
// can also be set in .cargo/config or with and ENV
402401
"mtime-on-use" => self.mtime_on_use = parse_empty(k, v)?,
403-
"install-upgrade" => self.install_upgrade = parse_empty(k, v)?,
404402
"named-profiles" => self.named_profiles = parse_empty(k, v)?,
405403
"binary-dep-depinfo" => self.binary_dep_depinfo = parse_empty(k, v)?,
406404
"build-std" => {

src/cargo/ops/common_for_install_and_uninstall.rs

Lines changed: 42 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -18,33 +18,31 @@ use crate::util::{FileLock, Filesystem};
1818

1919
/// On-disk tracking for which package installed which binary.
2020
///
21-
/// v1 is an older style, v2 is a new (experimental) style that tracks more
22-
/// information. The new style is only enabled with the `-Z install-upgrade`
23-
/// flag (which sets the `unstable_upgrade` flag). v1 is still considered the
24-
/// source of truth. When v2 is used, it will sync with any changes with v1,
25-
/// and will continue to update v1.
21+
/// v1 is an older style, v2 is a new style that tracks more information, and
22+
/// is both backwards and forwards compatible. Cargo keeps both files in sync,
23+
/// updating both v1 and v2 at the same time. Additionally, if it detects
24+
/// changes in v1 that are not in v2 (such as when an older version of Cargo
25+
/// is used), it will automatically propagate those changes to v2.
2626
///
2727
/// This maintains a filesystem lock, preventing other instances of Cargo from
2828
/// modifying at the same time. Drop the value to unlock.
2929
///
30-
/// If/when v2 is stabilized, it is intended that v1 is retained for a while
31-
/// during a longish transition period, and then v1 can be removed.
30+
/// It is intended that v1 should be retained for a while during a longish
31+
/// transition period, and then v1 can be removed.
3232
pub struct InstallTracker {
3333
v1: CrateListingV1,
3434
v2: CrateListingV2,
3535
v1_lock: FileLock,
36-
v2_lock: Option<FileLock>,
37-
unstable_upgrade: bool,
36+
v2_lock: FileLock,
3837
}
3938

4039
/// Tracking information for the set of installed packages.
41-
///
42-
/// This v2 format is unstable and requires the `-Z unstable-upgrade` option
43-
/// to enable.
4440
#[derive(Default, Deserialize, Serialize)]
4541
struct CrateListingV2 {
42+
/// Map of every installed package.
4643
installs: BTreeMap<PackageId, InstallInfo>,
47-
/// Forwards compatibility.
44+
/// Forwards compatibility. Unknown keys from future versions of Cargo
45+
/// will be stored here and retained when the file is saved.
4846
#[serde(flatten)]
4947
other: BTreeMap<String, serde_json::Value>,
5048
}
@@ -56,7 +54,7 @@ struct CrateListingV2 {
5654
/// determine if it needs to be rebuilt/reinstalled. If nothing has changed,
5755
/// then Cargo will inform the user that it is "up to date".
5856
///
59-
/// This is only used for the (unstable) v2 format.
57+
/// This is only used for the v2 format.
6058
#[derive(Debug, Deserialize, Serialize)]
6159
struct InstallInfo {
6260
/// Version requested via `--version`.
@@ -87,19 +85,15 @@ struct InstallInfo {
8785
/// Tracking information for the set of installed packages.
8886
#[derive(Default, Deserialize, Serialize)]
8987
pub struct CrateListingV1 {
88+
/// Map of installed package id to the set of binary names for that package.
9089
v1: BTreeMap<PackageId, BTreeSet<String>>,
9190
}
9291

9392
impl InstallTracker {
9493
/// Create an InstallTracker from information on disk.
9594
pub fn load(config: &Config, root: &Filesystem) -> CargoResult<InstallTracker> {
96-
let unstable_upgrade = config.cli_unstable().install_upgrade;
9795
let v1_lock = root.open_rw(Path::new(".crates.toml"), config, "crate metadata")?;
98-
let v2_lock = if unstable_upgrade {
99-
Some(root.open_rw(Path::new(".crates2.json"), config, "crate metadata")?)
100-
} else {
101-
None
102-
};
96+
let v2_lock = root.open_rw(Path::new(".crates2.json"), config, "crate metadata")?;
10397

10498
let v1 = (|| -> CargoResult<_> {
10599
let mut contents = String::new();
@@ -119,26 +113,21 @@ impl InstallTracker {
119113
})?;
120114

121115
let v2 = (|| -> CargoResult<_> {
122-
match &v2_lock {
123-
Some(lock) => {
124-
let mut contents = String::new();
125-
lock.file().read_to_string(&mut contents)?;
126-
let mut v2 = if contents.is_empty() {
127-
CrateListingV2::default()
128-
} else {
129-
serde_json::from_str(&contents)
130-
.chain_err(|| format_err!("invalid JSON found for metadata"))?
131-
};
132-
v2.sync_v1(&v1)?;
133-
Ok(v2)
134-
}
135-
None => Ok(CrateListingV2::default()),
136-
}
116+
let mut contents = String::new();
117+
v2_lock.file().read_to_string(&mut contents)?;
118+
let mut v2 = if contents.is_empty() {
119+
CrateListingV2::default()
120+
} else {
121+
serde_json::from_str(&contents)
122+
.chain_err(|| format_err!("invalid JSON found for metadata"))?
123+
};
124+
v2.sync_v1(&v1)?;
125+
Ok(v2)
137126
})()
138127
.chain_err(|| {
139128
format_err!(
140129
"failed to parse crate metadata at `{}`",
141-
v2_lock.as_ref().unwrap().path().to_string_lossy()
130+
v2_lock.path().to_string_lossy()
142131
)
143132
})?;
144133

@@ -147,7 +136,6 @@ impl InstallTracker {
147136
v2,
148137
v1_lock,
149138
v2_lock,
150-
unstable_upgrade,
151139
})
152140
}
153141

@@ -204,7 +192,7 @@ impl InstallTracker {
204192

205193
// If both sets are the same length, that means all duplicates come
206194
// from packages with the same name.
207-
if self.unstable_upgrade && matching_duplicates.len() == duplicates.len() {
195+
if matching_duplicates.len() == duplicates.len() {
208196
// Determine if it is dirty or fresh.
209197
let source_id = pkg.package_id().source_id();
210198
if source_id.is_path() {
@@ -265,11 +253,8 @@ impl InstallTracker {
265253
.filter_map(|name| {
266254
if !dst.join(&name).exists() {
267255
None
268-
} else if self.unstable_upgrade {
269-
let p = self.v2.package_for_bin(name);
270-
Some((name.clone(), p))
271256
} else {
272-
let p = self.v1.package_for_bin(name);
257+
let p = self.v2.package_for_bin(name);
273258
Some((name.clone(), p))
274259
}
275260
})
@@ -286,10 +271,8 @@ impl InstallTracker {
286271
target: &str,
287272
rustc: &str,
288273
) {
289-
if self.unstable_upgrade {
290-
self.v2
291-
.mark_installed(package, bins, version_req, opts, target, rustc)
292-
}
274+
self.v2
275+
.mark_installed(package, bins, version_req, opts, target, rustc);
293276
self.v1.mark_installed(package, bins);
294277
}
295278

@@ -302,14 +285,12 @@ impl InstallTracker {
302285
)
303286
})?;
304287

305-
if self.unstable_upgrade {
306-
self.v2.save(self.v2_lock.as_ref().unwrap()).chain_err(|| {
307-
format_err!(
308-
"failed to write crate metadata at `{}`",
309-
self.v2_lock.as_ref().unwrap().path().to_string_lossy()
310-
)
311-
})?;
312-
}
288+
self.v2.save(&self.v2_lock).chain_err(|| {
289+
format_err!(
290+
"failed to write crate metadata at `{}`",
291+
self.v2_lock.path().to_string_lossy()
292+
)
293+
})?;
313294
Ok(())
314295
}
315296

@@ -329,20 +310,11 @@ impl InstallTracker {
329310
/// Remove a package from the tracker.
330311
pub fn remove(&mut self, pkg_id: PackageId, bins: &BTreeSet<String>) {
331312
self.v1.remove(pkg_id, bins);
332-
if self.unstable_upgrade {
333-
self.v2.remove(pkg_id, bins);
334-
}
313+
self.v2.remove(pkg_id, bins);
335314
}
336315
}
337316

338317
impl CrateListingV1 {
339-
fn package_for_bin(&self, bin_name: &str) -> Option<PackageId> {
340-
self.v1
341-
.iter()
342-
.find(|(_, bins)| bins.contains(bin_name))
343-
.map(|(pkg_id, _)| *pkg_id)
344-
}
345-
346318
fn mark_installed(&mut self, pkg: &Package, bins: &BTreeSet<String>) {
347319
// Remove bins from any other packages.
348320
for other_bins in self.v1.values_mut() {
@@ -600,24 +572,11 @@ where
600572
match v.to_semver() {
601573
Ok(v) => Some(format!("={}", v)),
602574
Err(e) => {
603-
let mut msg = if config.cli_unstable().install_upgrade {
604-
format!(
605-
"the `--vers` provided, `{}`, is \
606-
not a valid semver version: {}\n",
607-
v, e
608-
)
609-
} else {
610-
format!(
611-
"the `--vers` provided, `{}`, is \
612-
not a valid semver version\n\n\
613-
historically Cargo treated this \
614-
as a semver version requirement \
615-
accidentally\nand will continue \
616-
to do so, but this behavior \
617-
will be removed eventually",
618-
v
619-
)
620-
};
575+
let mut msg = format!(
576+
"the `--vers` provided, `{}`, is \
577+
not a valid semver version: {}\n",
578+
v, e
579+
);
621580

622581
// If it is not a valid version but it is a valid version
623582
// requirement, add a note to the warning
@@ -628,12 +587,7 @@ where
628587
v
629588
));
630589
}
631-
if config.cli_unstable().install_upgrade {
632-
bail!(msg);
633-
} else {
634-
config.shell().warn(&msg)?;
635-
}
636-
Some(v.to_string())
590+
bail!(msg);
637591
}
638592
}
639593
}

src/doc/man/cargo-install.adoc

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,20 @@ crate has multiple binaries, the `--bin` argument can selectively install only
3737
one of them, and if you'd rather install examples the `--example` argument can
3838
be used as well.
3939

40+
If the package is already installed, Cargo will reinstall it if the installed
41+
version does not appear to be up-to-date. If any of the following values
42+
change, then Cargo will reinstall the package:
43+
44+
- The package version and source.
45+
- The set of binary names installed.
46+
- The chosen features.
47+
- The release mode (`--debug`).
48+
- The target (`--target`).
49+
50+
Installing with `--path` will always build and install, unless there are
51+
conflicting binaries from another package. The `--force` flag may be used to
52+
force Cargo to always reinstall the package.
53+
4054
If the source is crates.io or `--git` then by default the crate will be built
4155
in a temporary target directory. To avoid this, the target directory can be
4256
specified by setting the `CARGO_TARGET_DIR` environment variable to a relative
@@ -63,7 +77,13 @@ available.
6377

6478
*--vers* _VERSION_::
6579
*--version* _VERSION_::
66-
Specify a version to install.
80+
Specify a version to install. This may be a
81+
linkcargo:reference/specifying-dependencies.md[version requirement], like
82+
`~1.2`, to have Cargo select the newest version from the given
83+
requirement. If the version does not have a requirement operator (such as
84+
`^` or `~`), then it must be in the form _MAJOR.MINOR.PATCH_, and will
85+
install exactly that version; it is *not* treated as a caret requirement
86+
like Cargo dependencies are.
6787

6888
*--git* _URL_::
6989
Git URL to install the specified crate from.
@@ -85,9 +105,18 @@ available.
85105

86106
*-f*::
87107
*--force*::
88-
Force overwriting existing crates or binaries. This can be used to
89-
reinstall or upgrade a crate.
90-
108+
Force overwriting existing crates or binaries. This can be used if a
109+
package has installed a binary with the same name as another package. This
110+
is also useful if something has changed on the system that you want to
111+
rebuild with, such as a newer version of `rustc`.
112+
113+
*--no-track*::
114+
By default, Cargo keeps track of the installed packages with a metadata
115+
file stored in the installation root directory. This flag tells Cargo not
116+
to use or create that file. With this flag, Cargo will refuse to overwrite
117+
any existing files unless the `--force` flag is used. This also disables
118+
Cargo's ability to protect against multiple concurrent invocations of
119+
Cargo installing at the same time.
91120

92121
*--bin* _NAME_...::
93122
Install only the specified binary.
@@ -137,13 +166,17 @@ include::section-exit-status.adoc[]
137166

138167
== EXAMPLES
139168

140-
. Install a package from crates.io:
169+
. Install or upgrade a package from crates.io:
141170

142171
cargo install ripgrep
143172

144-
. Reinstall or upgrade a package:
173+
. Install or reinstall the package in the current directory:
174+
175+
cargo install --path .
176+
177+
. View the list of installed packages:
145178

146-
cargo install ripgrep --force
179+
cargo install --list
147180

148181
== SEE ALSO
149182
man:cargo[1], man:cargo-uninstall[1], man:cargo-search[1], man:cargo-publish[1]

0 commit comments

Comments
 (0)