mirror of
https://github.com/rust-lang/cargo.git
synced 2025-10-01 11:30:39 +00:00
Auto merge of #11647 - peterallin:peterallin/11617, r=weihanglo
Make cargo install report needed features ### What does this PR try to resolve? The problem described in issue #11617 where cargo tells the user, that no binaries are available because of the chosen features, but does not tell which features could be enabled to fix the situation. Fixes #11617. ### How should we test and review this PR? Try to cargo install a crate, where all binaries need some features enabled, without enabling the features and check the error message. The test suite already contains tests for this.
This commit is contained in:
commit
2c30ebe1ea
@ -4,7 +4,7 @@ use std::sync::Arc;
|
|||||||
use std::{env, fs};
|
use std::{env, fs};
|
||||||
|
|
||||||
use crate::core::compiler::{CompileKind, DefaultExecutor, Executor, UnitOutput};
|
use crate::core::compiler::{CompileKind, DefaultExecutor, Executor, UnitOutput};
|
||||||
use crate::core::{Dependency, Edition, Package, PackageId, Source, SourceId, Workspace};
|
use crate::core::{Dependency, Edition, Package, PackageId, Source, SourceId, Target, Workspace};
|
||||||
use crate::ops::{common_for_install_and_uninstall::*, FilterRule};
|
use crate::ops::{common_for_install_and_uninstall::*, FilterRule};
|
||||||
use crate::ops::{CompileFilter, Packages};
|
use crate::ops::{CompileFilter, Packages};
|
||||||
use crate::sources::{GitSource, PathSource, SourceConfigMap};
|
use crate::sources::{GitSource, PathSource, SourceConfigMap};
|
||||||
@ -14,6 +14,7 @@ use crate::{drop_println, ops};
|
|||||||
|
|
||||||
use anyhow::{bail, format_err, Context as _};
|
use anyhow::{bail, format_err, Context as _};
|
||||||
use cargo_util::paths;
|
use cargo_util::paths;
|
||||||
|
use itertools::Itertools;
|
||||||
use semver::VersionReq;
|
use semver::VersionReq;
|
||||||
use tempfile::Builder as TempFileBuilder;
|
use tempfile::Builder as TempFileBuilder;
|
||||||
|
|
||||||
@ -360,10 +361,16 @@ impl<'cfg, 'a> InstallablePackage<'cfg, 'a> {
|
|||||||
//
|
//
|
||||||
// Note that we know at this point that _if_ bins or examples is set to `::Just`,
|
// Note that we know at this point that _if_ bins or examples is set to `::Just`,
|
||||||
// they're `::Just([])`, which is `FilterRule::none()`.
|
// they're `::Just([])`, which is `FilterRule::none()`.
|
||||||
if self.pkg.targets().iter().any(|t| t.is_executable()) {
|
let binaries: Vec<_> = self
|
||||||
|
.pkg
|
||||||
|
.targets()
|
||||||
|
.iter()
|
||||||
|
.filter(|t| t.is_executable())
|
||||||
|
.collect();
|
||||||
|
if !binaries.is_empty() {
|
||||||
self.config
|
self.config
|
||||||
.shell()
|
.shell()
|
||||||
.warn("none of the package's binaries are available for install using the selected features")?;
|
.warn(make_warning_about_missing_features(&binaries))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
@ -546,6 +553,45 @@ impl<'cfg, 'a> InstallablePackage<'cfg, 'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn make_warning_about_missing_features(binaries: &[&Target]) -> String {
|
||||||
|
let max_targets_listed = 7;
|
||||||
|
let target_features_message = binaries
|
||||||
|
.iter()
|
||||||
|
.take(max_targets_listed)
|
||||||
|
.map(|b| {
|
||||||
|
let name = b.description_named();
|
||||||
|
let features = b
|
||||||
|
.required_features()
|
||||||
|
.unwrap_or(&Vec::new())
|
||||||
|
.iter()
|
||||||
|
.map(|f| format!("`{f}`"))
|
||||||
|
.join(", ");
|
||||||
|
format!(" {name} requires the features: {features}")
|
||||||
|
})
|
||||||
|
.join("\n");
|
||||||
|
|
||||||
|
let additional_bins_message = if binaries.len() > max_targets_listed {
|
||||||
|
format!(
|
||||||
|
"\n{} more targets also requires features not enabled. See them in the Cargo.toml file.",
|
||||||
|
binaries.len() - max_targets_listed
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
"".into()
|
||||||
|
};
|
||||||
|
|
||||||
|
let example_features = binaries[0]
|
||||||
|
.required_features()
|
||||||
|
.map(|f| f.join(" "))
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
format!(
|
||||||
|
"\
|
||||||
|
none of the package's binaries are available for install using the selected features
|
||||||
|
{target_features_message}{additional_bins_message}
|
||||||
|
Consider enabling some of the needed features by passing, e.g., `--features=\"{example_features}\"`"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn install(
|
pub fn install(
|
||||||
config: &Config,
|
config: &Config,
|
||||||
root: Option<&str>,
|
root: Option<&str>,
|
||||||
|
@ -640,6 +640,9 @@ fn install_default_features() {
|
|||||||
[INSTALLING] foo v0.0.1 ([..])
|
[INSTALLING] foo v0.0.1 ([..])
|
||||||
[FINISHED] release [optimized] target(s) in [..]
|
[FINISHED] release [optimized] target(s) in [..]
|
||||||
[WARNING] none of the package's binaries are available for install using the selected features
|
[WARNING] none of the package's binaries are available for install using the selected features
|
||||||
|
bin \"foo\" requires the features: `a`
|
||||||
|
example \"foo\" requires the features: `a`
|
||||||
|
Consider enabling some of the needed features by passing, e.g., `--features=\"a\"`
|
||||||
",
|
",
|
||||||
)
|
)
|
||||||
.run();
|
.run();
|
||||||
@ -792,6 +795,11 @@ fn install_multiple_required_features() {
|
|||||||
[INSTALLING] foo v0.0.1 ([..])
|
[INSTALLING] foo v0.0.1 ([..])
|
||||||
[FINISHED] release [optimized] target(s) in [..]
|
[FINISHED] release [optimized] target(s) in [..]
|
||||||
[WARNING] none of the package's binaries are available for install using the selected features
|
[WARNING] none of the package's binaries are available for install using the selected features
|
||||||
|
bin \"foo_1\" requires the features: `b`, `c`
|
||||||
|
bin \"foo_2\" requires the features: `a`
|
||||||
|
example \"foo_3\" requires the features: `b`, `c`
|
||||||
|
example \"foo_4\" requires the features: `a`
|
||||||
|
Consider enabling some of the needed features by passing, e.g., `--features=\"b c\"`
|
||||||
",
|
",
|
||||||
)
|
)
|
||||||
.run();
|
.run();
|
||||||
@ -802,6 +810,11 @@ fn install_multiple_required_features() {
|
|||||||
[WARNING] Target filter `bins` specified, but no targets matched. This is a no-op
|
[WARNING] Target filter `bins` specified, but no targets matched. This is a no-op
|
||||||
[FINISHED] release [optimized] target(s) in [..]
|
[FINISHED] release [optimized] target(s) in [..]
|
||||||
[WARNING] none of the package's binaries are available for install using the selected features
|
[WARNING] none of the package's binaries are available for install using the selected features
|
||||||
|
bin \"foo_1\" requires the features: `b`, `c`
|
||||||
|
bin \"foo_2\" requires the features: `a`
|
||||||
|
example \"foo_3\" requires the features: `b`, `c`
|
||||||
|
example \"foo_4\" requires the features: `a`
|
||||||
|
Consider enabling some of the needed features by passing, e.g., `--features=\"b c\"`
|
||||||
",
|
",
|
||||||
)
|
)
|
||||||
.run();
|
.run();
|
||||||
@ -812,6 +825,11 @@ fn install_multiple_required_features() {
|
|||||||
[WARNING] Target filter `examples` specified, but no targets matched. This is a no-op
|
[WARNING] Target filter `examples` specified, but no targets matched. This is a no-op
|
||||||
[FINISHED] release [optimized] target(s) in [..]
|
[FINISHED] release [optimized] target(s) in [..]
|
||||||
[WARNING] none of the package's binaries are available for install using the selected features
|
[WARNING] none of the package's binaries are available for install using the selected features
|
||||||
|
bin \"foo_1\" requires the features: `b`, `c`
|
||||||
|
bin \"foo_2\" requires the features: `a`
|
||||||
|
example \"foo_3\" requires the features: `b`, `c`
|
||||||
|
example \"foo_4\" requires the features: `a`
|
||||||
|
Consider enabling some of the needed features by passing, e.g., `--features=\"b c\"`
|
||||||
",
|
",
|
||||||
)
|
)
|
||||||
.run();
|
.run();
|
||||||
@ -822,6 +840,11 @@ fn install_multiple_required_features() {
|
|||||||
[WARNING] Target filters `bins`, `examples` specified, but no targets matched. This is a no-op
|
[WARNING] Target filters `bins`, `examples` specified, but no targets matched. This is a no-op
|
||||||
[FINISHED] release [optimized] target(s) in [..]
|
[FINISHED] release [optimized] target(s) in [..]
|
||||||
[WARNING] none of the package's binaries are available for install using the selected features
|
[WARNING] none of the package's binaries are available for install using the selected features
|
||||||
|
bin \"foo_1\" requires the features: `b`, `c`
|
||||||
|
bin \"foo_2\" requires the features: `a`
|
||||||
|
example \"foo_3\" requires the features: `b`, `c`
|
||||||
|
example \"foo_4\" requires the features: `a`
|
||||||
|
Consider enabling some of the needed features by passing, e.g., `--features=\"b c\"`
|
||||||
",
|
",
|
||||||
)
|
)
|
||||||
.run();
|
.run();
|
||||||
@ -1080,6 +1103,9 @@ Consider enabling them by passing, e.g., `--features=\"bar/a\"`
|
|||||||
[INSTALLING] foo v0.0.1 ([..])
|
[INSTALLING] foo v0.0.1 ([..])
|
||||||
[FINISHED] release [optimized] target(s) in [..]
|
[FINISHED] release [optimized] target(s) in [..]
|
||||||
[WARNING] none of the package's binaries are available for install using the selected features
|
[WARNING] none of the package's binaries are available for install using the selected features
|
||||||
|
bin \"foo\" requires the features: `bar/a`
|
||||||
|
example \"foo\" requires the features: `bar/a`
|
||||||
|
Consider enabling some of the needed features by passing, e.g., `--features=\"bar/a\"`
|
||||||
",
|
",
|
||||||
)
|
)
|
||||||
.run();
|
.run();
|
||||||
@ -1333,3 +1359,94 @@ Consider enabling them by passing, e.g., `--features=\"a1/f1\"`
|
|||||||
.with_stdout("a1 f1\na2 f2")
|
.with_stdout("a1 f1\na2 f2")
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cargo_test]
|
||||||
|
fn truncated_install_warning_message() {
|
||||||
|
let p = project()
|
||||||
|
.file(
|
||||||
|
"Cargo.toml",
|
||||||
|
r#"
|
||||||
|
[package]
|
||||||
|
name = "foo"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
feature1 = []
|
||||||
|
feature2 = []
|
||||||
|
feature3 = []
|
||||||
|
feature4 = []
|
||||||
|
feature5 = []
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "foo1"
|
||||||
|
required-features = ["feature1", "feature2", "feature3"]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "foo2"
|
||||||
|
required-features = ["feature2"]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "foo3"
|
||||||
|
required-features = ["feature3"]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "foo4"
|
||||||
|
required-features = ["feature4", "feature1"]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "foo5"
|
||||||
|
required-features = ["feature1", "feature2", "feature3", "feature4", "feature5"]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "foo6"
|
||||||
|
required-features = ["feature1", "feature2", "feature3", "feature4", "feature5"]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "foo7"
|
||||||
|
required-features = ["feature1", "feature2", "feature3", "feature4", "feature5"]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "foo8"
|
||||||
|
required-features = ["feature1", "feature2", "feature3", "feature4", "feature5"]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "foo9"
|
||||||
|
required-features = ["feature1", "feature2", "feature3", "feature4", "feature5"]
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "foo10"
|
||||||
|
required-features = ["feature1", "feature2", "feature3", "feature4", "feature5"]
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "example1"
|
||||||
|
required-features = ["feature1", "feature2"]
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.file("src/bin/foo1.rs", "fn main() {}")
|
||||||
|
.file("src/bin/foo2.rs", "fn main() {}")
|
||||||
|
.file("src/bin/foo3.rs", "fn main() {}")
|
||||||
|
.file("src/bin/foo4.rs", "fn main() {}")
|
||||||
|
.file("src/bin/foo5.rs", "fn main() {}")
|
||||||
|
.file("src/bin/foo6.rs", "fn main() {}")
|
||||||
|
.file("src/bin/foo7.rs", "fn main() {}")
|
||||||
|
.file("src/bin/foo8.rs", "fn main() {}")
|
||||||
|
.file("src/bin/foo9.rs", "fn main() {}")
|
||||||
|
.file("src/bin/foo10.rs", "fn main() {}")
|
||||||
|
.file("examples/example1.rs", "fn main() {}")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
p.cargo("install --path .").with_stderr("\
|
||||||
|
[INSTALLING] foo v0.1.0 ([..])
|
||||||
|
[FINISHED] release [optimized] target(s) in [..]
|
||||||
|
[WARNING] none of the package's binaries are available for install using the selected features
|
||||||
|
bin \"foo1\" requires the features: `feature1`, `feature2`, `feature3`
|
||||||
|
bin \"foo2\" requires the features: `feature2`
|
||||||
|
bin \"foo3\" requires the features: `feature3`
|
||||||
|
bin \"foo4\" requires the features: `feature4`, `feature1`
|
||||||
|
bin \"foo5\" requires the features: `feature1`, `feature2`, `feature3`, `feature4`, `feature5`
|
||||||
|
bin \"foo6\" requires the features: `feature1`, `feature2`, `feature3`, `feature4`, `feature5`
|
||||||
|
bin \"foo7\" requires the features: `feature1`, `feature2`, `feature3`, `feature4`, `feature5`
|
||||||
|
4 more targets also requires features not enabled. See them in the Cargo.toml file.
|
||||||
|
Consider enabling some of the needed features by passing, e.g., `--features=\"feature1 feature2 feature3\"`").run();
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user