Auto merge of #9602 - ehuss:diesel-warning, r=alexcrichton

Add a compatibility notice for diesel and the new resolver.

This adds a notice about a compatibility issue with diesel and the new feature resolver. This will display a notice if it detects the scenario where diesel causes a build error.  It also prints a not when using `cargo fix --edition` when it detects a setup that may fail.
This commit is contained in:
bors 2021-06-21 15:43:27 +00:00
commit f2c22a3690
2 changed files with 80 additions and 2 deletions

View file

@ -50,6 +50,7 @@
//! improved.
use std::cell::Cell;
use std::collections::BTreeSet;
use std::collections::{BTreeMap, HashMap, HashSet};
use std::io;
use std::marker;
@ -74,9 +75,11 @@ use super::{BuildContext, BuildPlan, CompileMode, Context, Unit};
use crate::core::compiler::future_incompat::{
FutureBreakageItem, OnDiskReport, FUTURE_INCOMPAT_FILE,
};
use crate::core::{PackageId, Shell, TargetKind};
use crate::core::resolver::ResolveBehavior;
use crate::core::{FeatureValue, PackageId, Shell, TargetKind};
use crate::drop_eprint;
use crate::util::diagnostic_server::{self, DiagnosticPrinter};
use crate::util::interning::InternedString;
use crate::util::machine_message::{self, Message as _};
use crate::util::CargoResult;
use crate::util::{self, internal, profile};
@ -607,6 +610,7 @@ impl<'cfg> DrainState<'cfg> {
Err(e) => {
let msg = "The following warnings were emitted during compilation:";
self.emit_warnings(Some(msg), &unit, cx)?;
self.back_compat_notice(cx, &unit)?;
return Err(e);
}
}
@ -1154,4 +1158,59 @@ impl<'cfg> DrainState<'cfg> {
}
Ok(())
}
fn back_compat_notice(&self, cx: &Context<'_, '_>, unit: &Unit) -> CargoResult<()> {
if unit.pkg.name() != "diesel"
|| unit.pkg.version().major != 1
|| cx.bcx.ws.resolve_behavior() == ResolveBehavior::V1
|| !unit.pkg.package_id().source_id().is_registry()
|| !unit.features.is_empty()
{
return Ok(());
}
let other_diesel = match cx
.bcx
.unit_graph
.keys()
.filter(|unit| unit.pkg.name() == "diesel" && !unit.features.is_empty())
.next()
{
Some(u) => u,
// Unlikely due to features.
None => return Ok(()),
};
let mut features_suggestion: BTreeSet<_> = other_diesel.features.iter().collect();
let fmap = other_diesel.pkg.summary().features();
// Remove any unnecessary features.
for feature in &other_diesel.features {
if let Some(feats) = fmap.get(feature) {
for feat in feats {
if let FeatureValue::Feature(f) = feat {
features_suggestion.remove(&f);
}
}
}
}
features_suggestion.remove(&InternedString::new("default"));
let features_suggestion = toml::to_string(&features_suggestion).unwrap();
cx.bcx.config.shell().note(&format!(
"\
This error may be due to an interaction between diesel and Cargo's new
feature resolver. Some workarounds you may want to consider:
- Add a build-dependency in Cargo.toml on diesel to force Cargo to add the appropriate
features. This may look something like this:
[build-dependencies]
diesel = {{ version = \"{}\", features = {} }}
- Try using the previous resolver by setting `resolver = \"1\"` in `Cargo.toml`
(see <https://doc.rust-lang.org/cargo/reference/resolver.html#resolver-versions>
for more information).
",
unit.pkg.version(),
features_suggestion
))?;
Ok(())
}
}

View file

@ -53,7 +53,7 @@ use rustfix::{self, CodeFix};
use crate::core::compiler::RustcTargetData;
use crate::core::resolver::features::{FeatureOpts, FeatureResolver};
use crate::core::resolver::{HasDevUnits, ResolveBehavior};
use crate::core::resolver::{HasDevUnits, Resolve, ResolveBehavior};
use crate::core::{Edition, MaybePackage, Workspace};
use crate::ops::{self, CompileOptions};
use crate::util::diagnostic_server::{Message, RustfixDiagnosticServer};
@ -292,6 +292,25 @@ fn check_resolver_change(ws: &Workspace<'_>, opts: &FixOptions) -> CargoResult<(
report(differences.features, "features");
report(differences.optional_deps, "optional dependency");
drop_eprint!(config, "\n");
report_maybe_diesel(config, &ws_resolve.targeted_resolve)?;
Ok(())
}
fn report_maybe_diesel(config: &Config, resolve: &Resolve) -> CargoResult<()> {
if resolve
.iter()
.any(|pid| pid.name() == "diesel" && pid.version().major == 1)
&& resolve.iter().any(|pid| pid.name() == "diesel_migrations")
{
config.shell().note(
"\
This project appears to use both diesel and diesel_migrations. These packages have
a known issue where the build may fail due to the version 2 resolver preventing
feature unification between those two packages. See
<https://github.com/rust-lang/cargo/issues/9450> for some potential workarounds.
",
)?;
}
Ok(())
}