mirror of
https://github.com/rust-lang/cargo.git
synced 2025-10-01 11:30:39 +00:00
Auto merge of #12930 - epage:msrv-refactor, r=Eh2406
refactor(resolver): Consolidate logic in `VersionPreferences` ### What does this PR try to resolve? This makes customizing the resolver less intrusive by putting the logic in `VersionPreferences` and making it easy to add new priority cases to it. In particular, this is prep for tweaking the MSRV resolver to prefer compatible versions, rather than require them. See https://rust-lang.zulipchat.com/#narrow/stream/246057-t-cargo/topic/Alternative.20MSRV-aware.20resolver.20approach.3F ### How should we test and review this PR? Each step is broken down into its own commit for easier browsing ### Additional information
This commit is contained in:
commit
19a0404816
@ -12,7 +12,7 @@ use std::task::Poll;
|
|||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
use cargo::core::dependency::DepKind;
|
use cargo::core::dependency::DepKind;
|
||||||
use cargo::core::resolver::{self, ResolveOpts, VersionPreferences};
|
use cargo::core::resolver::{self, ResolveOpts, VersionOrdering, VersionPreferences};
|
||||||
use cargo::core::Resolve;
|
use cargo::core::Resolve;
|
||||||
use cargo::core::{Dependency, PackageId, Registry, Summary};
|
use cargo::core::{Dependency, PackageId, Registry, Summary};
|
||||||
use cargo::core::{GitReference, SourceId};
|
use cargo::core::{GitReference, SourceId};
|
||||||
@ -190,15 +190,17 @@ pub fn resolve_with_config_raw(
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
let opts = ResolveOpts::everything();
|
let opts = ResolveOpts::everything();
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let max_rust_version = None;
|
let mut version_prefs = VersionPreferences::default();
|
||||||
|
if config.cli_unstable().minimal_versions {
|
||||||
|
version_prefs.version_ordering(VersionOrdering::MinimumVersionsFirst)
|
||||||
|
}
|
||||||
let resolve = resolver::resolve(
|
let resolve = resolver::resolve(
|
||||||
&[(summary, opts)],
|
&[(summary, opts)],
|
||||||
&[],
|
&[],
|
||||||
&mut registry,
|
&mut registry,
|
||||||
&VersionPreferences::default(),
|
&version_prefs,
|
||||||
Some(config),
|
Some(config),
|
||||||
true,
|
true,
|
||||||
max_rust_version,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// The largest test in our suite takes less then 30 sec.
|
// The largest test in our suite takes less then 30 sec.
|
||||||
@ -982,14 +984,17 @@ fn meta_test_multiple_versions_strategy() {
|
|||||||
|
|
||||||
/// Assert `xs` contains `elems`
|
/// Assert `xs` contains `elems`
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn assert_contains<A: PartialEq>(xs: &[A], elems: &[A]) {
|
pub fn assert_contains<A: PartialEq + std::fmt::Debug>(xs: &[A], elems: &[A]) {
|
||||||
for elem in elems {
|
for elem in elems {
|
||||||
assert!(xs.contains(elem));
|
assert!(
|
||||||
|
xs.contains(elem),
|
||||||
|
"missing element\nset: {xs:?}\nmissing: {elem:?}"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn assert_same<A: PartialEq>(a: &[A], b: &[A]) {
|
pub fn assert_same<A: PartialEq + std::fmt::Debug>(a: &[A], b: &[A]) {
|
||||||
assert_eq!(a.len(), b.len());
|
assert_eq!(a.len(), b.len(), "not equal\n{a:?}\n{b:?}");
|
||||||
assert_contains(b, a);
|
assert_contains(b, a);
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,6 @@ use crate::core::{Dependency, FeatureValue, PackageId, PackageIdSpec, Registry,
|
|||||||
use crate::sources::source::QueryKind;
|
use crate::sources::source::QueryKind;
|
||||||
use crate::util::errors::CargoResult;
|
use crate::util::errors::CargoResult;
|
||||||
use crate::util::interning::InternedString;
|
use crate::util::interning::InternedString;
|
||||||
use crate::util::RustVersion;
|
|
||||||
|
|
||||||
use anyhow::Context as _;
|
use anyhow::Context as _;
|
||||||
use std::collections::{BTreeSet, HashMap, HashSet};
|
use std::collections::{BTreeSet, HashMap, HashSet};
|
||||||
@ -32,16 +31,11 @@ pub struct RegistryQueryer<'a> {
|
|||||||
pub registry: &'a mut (dyn Registry + 'a),
|
pub registry: &'a mut (dyn Registry + 'a),
|
||||||
replacements: &'a [(PackageIdSpec, Dependency)],
|
replacements: &'a [(PackageIdSpec, Dependency)],
|
||||||
version_prefs: &'a VersionPreferences,
|
version_prefs: &'a VersionPreferences,
|
||||||
/// If set the list of dependency candidates will be sorted by minimal
|
/// a cache of `Candidate`s that fulfil a `Dependency` (and whether `first_version`)
|
||||||
/// versions first. That allows `cargo update -Z minimal-versions` which will
|
registry_cache: HashMap<(Dependency, Option<VersionOrdering>), Poll<Rc<Vec<Summary>>>>,
|
||||||
/// specify minimum dependency versions to be used.
|
|
||||||
minimal_versions: bool,
|
|
||||||
max_rust_version: Option<RustVersion>,
|
|
||||||
/// a cache of `Candidate`s that fulfil a `Dependency` (and whether `first_minimal_version`)
|
|
||||||
registry_cache: HashMap<(Dependency, bool), Poll<Rc<Vec<Summary>>>>,
|
|
||||||
/// a cache of `Dependency`s that are required for a `Summary`
|
/// a cache of `Dependency`s that are required for a `Summary`
|
||||||
///
|
///
|
||||||
/// HACK: `first_minimal_version` is not kept in the cache key is it is 1:1 with
|
/// HACK: `first_version` is not kept in the cache key is it is 1:1 with
|
||||||
/// `parent.is_none()` (the first element of the cache key) as it doesn't change through
|
/// `parent.is_none()` (the first element of the cache key) as it doesn't change through
|
||||||
/// execution.
|
/// execution.
|
||||||
summary_cache: HashMap<
|
summary_cache: HashMap<
|
||||||
@ -57,15 +51,11 @@ impl<'a> RegistryQueryer<'a> {
|
|||||||
registry: &'a mut dyn Registry,
|
registry: &'a mut dyn Registry,
|
||||||
replacements: &'a [(PackageIdSpec, Dependency)],
|
replacements: &'a [(PackageIdSpec, Dependency)],
|
||||||
version_prefs: &'a VersionPreferences,
|
version_prefs: &'a VersionPreferences,
|
||||||
minimal_versions: bool,
|
|
||||||
max_rust_version: Option<&RustVersion>,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
RegistryQueryer {
|
RegistryQueryer {
|
||||||
registry,
|
registry,
|
||||||
replacements,
|
replacements,
|
||||||
version_prefs,
|
version_prefs,
|
||||||
minimal_versions,
|
|
||||||
max_rust_version: max_rust_version.cloned(),
|
|
||||||
registry_cache: HashMap::new(),
|
registry_cache: HashMap::new(),
|
||||||
summary_cache: HashMap::new(),
|
summary_cache: HashMap::new(),
|
||||||
used_replacements: HashMap::new(),
|
used_replacements: HashMap::new(),
|
||||||
@ -106,23 +96,20 @@ impl<'a> RegistryQueryer<'a> {
|
|||||||
pub fn query(
|
pub fn query(
|
||||||
&mut self,
|
&mut self,
|
||||||
dep: &Dependency,
|
dep: &Dependency,
|
||||||
first_minimal_version: bool,
|
first_version: Option<VersionOrdering>,
|
||||||
) -> Poll<CargoResult<Rc<Vec<Summary>>>> {
|
) -> Poll<CargoResult<Rc<Vec<Summary>>>> {
|
||||||
let registry_cache_key = (dep.clone(), first_minimal_version);
|
let registry_cache_key = (dep.clone(), first_version);
|
||||||
if let Some(out) = self.registry_cache.get(®istry_cache_key).cloned() {
|
if let Some(out) = self.registry_cache.get(®istry_cache_key).cloned() {
|
||||||
return out.map(Result::Ok);
|
return out.map(Result::Ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut ret = Vec::new();
|
let mut ret = Vec::new();
|
||||||
let ready = self.registry.query(dep, QueryKind::Exact, &mut |s| {
|
let ready = self.registry.query(dep, QueryKind::Exact, &mut |s| {
|
||||||
if self.max_rust_version.is_none() || s.rust_version() <= self.max_rust_version.as_ref()
|
|
||||||
{
|
|
||||||
ret.push(s);
|
ret.push(s);
|
||||||
}
|
|
||||||
})?;
|
})?;
|
||||||
if ready.is_pending() {
|
if ready.is_pending() {
|
||||||
self.registry_cache
|
self.registry_cache
|
||||||
.insert((dep.clone(), first_minimal_version), Poll::Pending);
|
.insert((dep.clone(), first_version), Poll::Pending);
|
||||||
return Poll::Pending;
|
return Poll::Pending;
|
||||||
}
|
}
|
||||||
for summary in ret.iter() {
|
for summary in ret.iter() {
|
||||||
@ -144,7 +131,7 @@ impl<'a> RegistryQueryer<'a> {
|
|||||||
Poll::Ready(s) => s.into_iter(),
|
Poll::Ready(s) => s.into_iter(),
|
||||||
Poll::Pending => {
|
Poll::Pending => {
|
||||||
self.registry_cache
|
self.registry_cache
|
||||||
.insert((dep.clone(), first_minimal_version), Poll::Pending);
|
.insert((dep.clone(), first_version), Poll::Pending);
|
||||||
return Poll::Pending;
|
return Poll::Pending;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -215,16 +202,8 @@ impl<'a> RegistryQueryer<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// When we attempt versions for a package we'll want to do so in a sorted fashion to pick
|
let first_version = first_version;
|
||||||
// the "best candidates" first. VersionPreferences implements this notion.
|
self.version_prefs.sort_summaries(&mut ret, first_version);
|
||||||
let ordering = if first_minimal_version || self.minimal_versions {
|
|
||||||
VersionOrdering::MinimumVersionsFirst
|
|
||||||
} else {
|
|
||||||
VersionOrdering::MaximumVersionsFirst
|
|
||||||
};
|
|
||||||
let first_version = first_minimal_version;
|
|
||||||
self.version_prefs
|
|
||||||
.sort_summaries(&mut ret, ordering, first_version);
|
|
||||||
|
|
||||||
let out = Poll::Ready(Rc::new(ret));
|
let out = Poll::Ready(Rc::new(ret));
|
||||||
|
|
||||||
@ -243,7 +222,7 @@ impl<'a> RegistryQueryer<'a> {
|
|||||||
parent: Option<PackageId>,
|
parent: Option<PackageId>,
|
||||||
candidate: &Summary,
|
candidate: &Summary,
|
||||||
opts: &ResolveOpts,
|
opts: &ResolveOpts,
|
||||||
first_minimal_version: bool,
|
first_version: Option<VersionOrdering>,
|
||||||
) -> ActivateResult<Rc<(HashSet<InternedString>, Rc<Vec<DepInfo>>)>> {
|
) -> ActivateResult<Rc<(HashSet<InternedString>, Rc<Vec<DepInfo>>)>> {
|
||||||
// if we have calculated a result before, then we can just return it,
|
// if we have calculated a result before, then we can just return it,
|
||||||
// as it is a "pure" query of its arguments.
|
// as it is a "pure" query of its arguments.
|
||||||
@ -263,8 +242,7 @@ impl<'a> RegistryQueryer<'a> {
|
|||||||
let mut all_ready = true;
|
let mut all_ready = true;
|
||||||
let mut deps = deps
|
let mut deps = deps
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(
|
.filter_map(|(dep, features)| match self.query(&dep, first_version) {
|
||||||
|(dep, features)| match self.query(&dep, first_minimal_version) {
|
|
||||||
Poll::Ready(Ok(candidates)) => Some(Ok((dep, candidates, features))),
|
Poll::Ready(Ok(candidates)) => Some(Ok((dep, candidates, features))),
|
||||||
Poll::Pending => {
|
Poll::Pending => {
|
||||||
all_ready = false;
|
all_ready = false;
|
||||||
@ -279,8 +257,7 @@ impl<'a> RegistryQueryer<'a> {
|
|||||||
describe_path_in_context(cx, &candidate.package_id()),
|
describe_path_in_context(cx, &candidate.package_id()),
|
||||||
)
|
)
|
||||||
})),
|
})),
|
||||||
},
|
})
|
||||||
)
|
|
||||||
.collect::<CargoResult<Vec<DepInfo>>>()?;
|
.collect::<CargoResult<Vec<DepInfo>>>()?;
|
||||||
|
|
||||||
// Attempt to resolve dependencies with fewer candidates before trying
|
// Attempt to resolve dependencies with fewer candidates before trying
|
||||||
|
@ -71,7 +71,6 @@ use crate::util::config::Config;
|
|||||||
use crate::util::errors::CargoResult;
|
use crate::util::errors::CargoResult;
|
||||||
use crate::util::network::PollExt;
|
use crate::util::network::PollExt;
|
||||||
use crate::util::profile;
|
use crate::util::profile;
|
||||||
use crate::util::RustVersion;
|
|
||||||
|
|
||||||
use self::context::Context;
|
use self::context::Context;
|
||||||
use self::dep_cache::RegistryQueryer;
|
use self::dep_cache::RegistryQueryer;
|
||||||
@ -139,39 +138,18 @@ pub fn resolve(
|
|||||||
version_prefs: &VersionPreferences,
|
version_prefs: &VersionPreferences,
|
||||||
config: Option<&Config>,
|
config: Option<&Config>,
|
||||||
check_public_visible_dependencies: bool,
|
check_public_visible_dependencies: bool,
|
||||||
mut max_rust_version: Option<&RustVersion>,
|
|
||||||
) -> CargoResult<Resolve> {
|
) -> CargoResult<Resolve> {
|
||||||
let _p = profile::start("resolving");
|
let _p = profile::start("resolving");
|
||||||
let minimal_versions = match config {
|
let first_version = match config {
|
||||||
Some(config) => config.cli_unstable().minimal_versions,
|
Some(config) if config.cli_unstable().direct_minimal_versions => {
|
||||||
None => false,
|
Some(VersionOrdering::MinimumVersionsFirst)
|
||||||
};
|
|
||||||
let direct_minimal_versions = match config {
|
|
||||||
Some(config) => config.cli_unstable().direct_minimal_versions,
|
|
||||||
None => false,
|
|
||||||
};
|
|
||||||
if !config
|
|
||||||
.map(|c| c.cli_unstable().msrv_policy)
|
|
||||||
.unwrap_or(false)
|
|
||||||
{
|
|
||||||
max_rust_version = None;
|
|
||||||
}
|
}
|
||||||
let mut registry = RegistryQueryer::new(
|
_ => None,
|
||||||
registry,
|
};
|
||||||
replacements,
|
let mut registry = RegistryQueryer::new(registry, replacements, version_prefs);
|
||||||
version_prefs,
|
|
||||||
minimal_versions,
|
|
||||||
max_rust_version,
|
|
||||||
);
|
|
||||||
let cx = loop {
|
let cx = loop {
|
||||||
let cx = Context::new(check_public_visible_dependencies);
|
let cx = Context::new(check_public_visible_dependencies);
|
||||||
let cx = activate_deps_loop(
|
let cx = activate_deps_loop(cx, &mut registry, summaries, first_version, config)?;
|
||||||
cx,
|
|
||||||
&mut registry,
|
|
||||||
summaries,
|
|
||||||
direct_minimal_versions,
|
|
||||||
config,
|
|
||||||
)?;
|
|
||||||
if registry.reset_pending() {
|
if registry.reset_pending() {
|
||||||
break cx;
|
break cx;
|
||||||
} else {
|
} else {
|
||||||
@ -223,7 +201,7 @@ fn activate_deps_loop(
|
|||||||
mut cx: Context,
|
mut cx: Context,
|
||||||
registry: &mut RegistryQueryer<'_>,
|
registry: &mut RegistryQueryer<'_>,
|
||||||
summaries: &[(Summary, ResolveOpts)],
|
summaries: &[(Summary, ResolveOpts)],
|
||||||
direct_minimal_versions: bool,
|
first_version: Option<VersionOrdering>,
|
||||||
config: Option<&Config>,
|
config: Option<&Config>,
|
||||||
) -> CargoResult<Context> {
|
) -> CargoResult<Context> {
|
||||||
let mut backtrack_stack = Vec::new();
|
let mut backtrack_stack = Vec::new();
|
||||||
@ -241,7 +219,7 @@ fn activate_deps_loop(
|
|||||||
registry,
|
registry,
|
||||||
None,
|
None,
|
||||||
summary.clone(),
|
summary.clone(),
|
||||||
direct_minimal_versions,
|
first_version,
|
||||||
opts,
|
opts,
|
||||||
);
|
);
|
||||||
match res {
|
match res {
|
||||||
@ -441,13 +419,13 @@ fn activate_deps_loop(
|
|||||||
dep.package_name(),
|
dep.package_name(),
|
||||||
candidate.version()
|
candidate.version()
|
||||||
);
|
);
|
||||||
let direct_minimal_version = false; // this is an indirect dependency
|
let first_version = None; // this is an indirect dependency
|
||||||
let res = activate(
|
let res = activate(
|
||||||
&mut cx,
|
&mut cx,
|
||||||
registry,
|
registry,
|
||||||
Some((&parent, &dep)),
|
Some((&parent, &dep)),
|
||||||
candidate,
|
candidate,
|
||||||
direct_minimal_version,
|
first_version,
|
||||||
&opts,
|
&opts,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -659,7 +637,7 @@ fn activate(
|
|||||||
registry: &mut RegistryQueryer<'_>,
|
registry: &mut RegistryQueryer<'_>,
|
||||||
parent: Option<(&Summary, &Dependency)>,
|
parent: Option<(&Summary, &Dependency)>,
|
||||||
candidate: Summary,
|
candidate: Summary,
|
||||||
first_minimal_version: bool,
|
first_version: Option<VersionOrdering>,
|
||||||
opts: &ResolveOpts,
|
opts: &ResolveOpts,
|
||||||
) -> ActivateResult<Option<(DepsFrame, Duration)>> {
|
) -> ActivateResult<Option<(DepsFrame, Duration)>> {
|
||||||
let candidate_pid = candidate.package_id();
|
let candidate_pid = candidate.package_id();
|
||||||
@ -716,7 +694,7 @@ fn activate(
|
|||||||
parent.map(|p| p.0.package_id()),
|
parent.map(|p| p.0.package_id()),
|
||||||
&candidate,
|
&candidate,
|
||||||
opts,
|
opts,
|
||||||
first_minimal_version,
|
first_version,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Record what list of features is active for this package.
|
// Record what list of features is active for this package.
|
||||||
@ -905,14 +883,14 @@ fn generalize_conflicting(
|
|||||||
})
|
})
|
||||||
{
|
{
|
||||||
for critical_parents_dep in critical_parents_deps.iter() {
|
for critical_parents_dep in critical_parents_deps.iter() {
|
||||||
// We only want `first_minimal_version=true` for direct dependencies of workspace
|
// We only want `first_version.is_some()` for direct dependencies of workspace
|
||||||
// members which isn't the case here as this has a `parent`
|
// members which isn't the case here as this has a `parent`
|
||||||
let first_minimal_version = false;
|
let first_version = None;
|
||||||
// A dep is equivalent to one of the things it can resolve to.
|
// A dep is equivalent to one of the things it can resolve to.
|
||||||
// Thus, if all the things it can resolve to have already ben determined
|
// Thus, if all the things it can resolve to have already ben determined
|
||||||
// to be conflicting, then we can just say that we conflict with the parent.
|
// to be conflicting, then we can just say that we conflict with the parent.
|
||||||
if let Some(others) = registry
|
if let Some(others) = registry
|
||||||
.query(critical_parents_dep, first_minimal_version)
|
.query(critical_parents_dep, first_version)
|
||||||
.expect("an already used dep now error!?")
|
.expect("an already used dep now error!?")
|
||||||
.expect("an already used dep now pending!?")
|
.expect("an already used dep now pending!?")
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -6,6 +6,7 @@ use std::collections::{HashMap, HashSet};
|
|||||||
|
|
||||||
use crate::core::{Dependency, PackageId, Summary};
|
use crate::core::{Dependency, PackageId, Summary};
|
||||||
use crate::util::interning::InternedString;
|
use crate::util::interning::InternedString;
|
||||||
|
use crate::util::RustVersion;
|
||||||
|
|
||||||
/// A collection of preferences for particular package versions.
|
/// A collection of preferences for particular package versions.
|
||||||
///
|
///
|
||||||
@ -18,9 +19,13 @@ use crate::util::interning::InternedString;
|
|||||||
pub struct VersionPreferences {
|
pub struct VersionPreferences {
|
||||||
try_to_use: HashSet<PackageId>,
|
try_to_use: HashSet<PackageId>,
|
||||||
prefer_patch_deps: HashMap<InternedString, HashSet<Dependency>>,
|
prefer_patch_deps: HashMap<InternedString, HashSet<Dependency>>,
|
||||||
|
version_ordering: VersionOrdering,
|
||||||
|
max_rust_version: Option<RustVersion>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Default, PartialEq, Eq, Hash, Debug)]
|
||||||
pub enum VersionOrdering {
|
pub enum VersionOrdering {
|
||||||
|
#[default]
|
||||||
MaximumVersionsFirst,
|
MaximumVersionsFirst,
|
||||||
MinimumVersionsFirst,
|
MinimumVersionsFirst,
|
||||||
}
|
}
|
||||||
@ -39,14 +44,29 @@ impl VersionPreferences {
|
|||||||
.insert(dep);
|
.insert(dep);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sort the given vector of summaries in-place, with all summaries presumed to be for
|
pub fn version_ordering(&mut self, ordering: VersionOrdering) {
|
||||||
/// the same package. Preferred versions appear first in the result, sorted by
|
self.version_ordering = ordering;
|
||||||
/// `version_ordering`, followed by non-preferred versions sorted the same way.
|
}
|
||||||
|
|
||||||
|
pub fn max_rust_version(&mut self, ver: Option<RustVersion>) {
|
||||||
|
self.max_rust_version = ver;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sort (and filter) the given vector of summaries in-place
|
||||||
|
///
|
||||||
|
/// Note: all summaries presumed to be for the same package.
|
||||||
|
///
|
||||||
|
/// Sort order:
|
||||||
|
/// 1. Preferred packages
|
||||||
|
/// 2. `first_version`, falling back to [`VersionPreferences::version_ordering`] when `None`
|
||||||
|
///
|
||||||
|
/// Filtering:
|
||||||
|
/// - [`VersionPreferences::max_rust_version`]
|
||||||
|
/// - `first_version`
|
||||||
pub fn sort_summaries(
|
pub fn sort_summaries(
|
||||||
&self,
|
&self,
|
||||||
summaries: &mut Vec<Summary>,
|
summaries: &mut Vec<Summary>,
|
||||||
version_ordering: VersionOrdering,
|
first_version: Option<VersionOrdering>,
|
||||||
first_version: bool,
|
|
||||||
) {
|
) {
|
||||||
let should_prefer = |pkg_id: &PackageId| {
|
let should_prefer = |pkg_id: &PackageId| {
|
||||||
self.try_to_use.contains(pkg_id)
|
self.try_to_use.contains(pkg_id)
|
||||||
@ -56,22 +76,24 @@ impl VersionPreferences {
|
|||||||
.map(|deps| deps.iter().any(|d| d.matches_id(*pkg_id)))
|
.map(|deps| deps.iter().any(|d| d.matches_id(*pkg_id)))
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
};
|
};
|
||||||
|
if self.max_rust_version.is_some() {
|
||||||
|
summaries.retain(|s| s.rust_version() <= self.max_rust_version.as_ref());
|
||||||
|
}
|
||||||
summaries.sort_unstable_by(|a, b| {
|
summaries.sort_unstable_by(|a, b| {
|
||||||
let prefer_a = should_prefer(&a.package_id());
|
let prefer_a = should_prefer(&a.package_id());
|
||||||
let prefer_b = should_prefer(&b.package_id());
|
let prefer_b = should_prefer(&b.package_id());
|
||||||
let previous_cmp = prefer_a.cmp(&prefer_b).reverse();
|
let previous_cmp = prefer_a.cmp(&prefer_b).reverse();
|
||||||
match previous_cmp {
|
if previous_cmp != Ordering::Equal {
|
||||||
Ordering::Equal => {
|
return previous_cmp;
|
||||||
|
}
|
||||||
|
|
||||||
let cmp = a.version().cmp(b.version());
|
let cmp = a.version().cmp(b.version());
|
||||||
match version_ordering {
|
match first_version.unwrap_or(self.version_ordering) {
|
||||||
VersionOrdering::MaximumVersionsFirst => cmp.reverse(),
|
VersionOrdering::MaximumVersionsFirst => cmp.reverse(),
|
||||||
VersionOrdering::MinimumVersionsFirst => cmp,
|
VersionOrdering::MinimumVersionsFirst => cmp,
|
||||||
}
|
}
|
||||||
}
|
|
||||||
_ => previous_cmp,
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
if first_version {
|
if first_version.is_some() {
|
||||||
let _ = summaries.split_off(1);
|
let _ = summaries.split_off(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -81,7 +103,6 @@ impl VersionPreferences {
|
|||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::core::SourceId;
|
use crate::core::SourceId;
|
||||||
use crate::util::RustVersion;
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
fn pkgid(name: &str, version: &str) -> PackageId {
|
fn pkgid(name: &str, version: &str) -> PackageId {
|
||||||
@ -96,7 +117,7 @@ mod test {
|
|||||||
Dependency::parse(name, Some(version), src_id).unwrap()
|
Dependency::parse(name, Some(version), src_id).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn summ(name: &str, version: &str) -> Summary {
|
fn summ(name: &str, version: &str, msrv: Option<&str>) -> Summary {
|
||||||
let pkg_id = pkgid(name, version);
|
let pkg_id = pkgid(name, version);
|
||||||
let features = BTreeMap::new();
|
let features = BTreeMap::new();
|
||||||
Summary::new(
|
Summary::new(
|
||||||
@ -104,7 +125,7 @@ mod test {
|
|||||||
Vec::new(),
|
Vec::new(),
|
||||||
&features,
|
&features,
|
||||||
None::<&String>,
|
None::<&String>,
|
||||||
None::<RustVersion>,
|
msrv.map(|m| m.parse().unwrap()),
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
@ -123,19 +144,21 @@ mod test {
|
|||||||
vp.prefer_package_id(pkgid("foo", "1.2.3"));
|
vp.prefer_package_id(pkgid("foo", "1.2.3"));
|
||||||
|
|
||||||
let mut summaries = vec![
|
let mut summaries = vec![
|
||||||
summ("foo", "1.2.4"),
|
summ("foo", "1.2.4", None),
|
||||||
summ("foo", "1.2.3"),
|
summ("foo", "1.2.3", None),
|
||||||
summ("foo", "1.1.0"),
|
summ("foo", "1.1.0", None),
|
||||||
summ("foo", "1.0.9"),
|
summ("foo", "1.0.9", None),
|
||||||
];
|
];
|
||||||
|
|
||||||
vp.sort_summaries(&mut summaries, VersionOrdering::MaximumVersionsFirst, false);
|
vp.version_ordering(VersionOrdering::MaximumVersionsFirst);
|
||||||
|
vp.sort_summaries(&mut summaries, None);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
describe(&summaries),
|
describe(&summaries),
|
||||||
"foo/1.2.3, foo/1.2.4, foo/1.1.0, foo/1.0.9".to_string()
|
"foo/1.2.3, foo/1.2.4, foo/1.1.0, foo/1.0.9".to_string()
|
||||||
);
|
);
|
||||||
|
|
||||||
vp.sort_summaries(&mut summaries, VersionOrdering::MinimumVersionsFirst, false);
|
vp.version_ordering(VersionOrdering::MinimumVersionsFirst);
|
||||||
|
vp.sort_summaries(&mut summaries, None);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
describe(&summaries),
|
describe(&summaries),
|
||||||
"foo/1.2.3, foo/1.0.9, foo/1.1.0, foo/1.2.4".to_string()
|
"foo/1.2.3, foo/1.0.9, foo/1.1.0, foo/1.2.4".to_string()
|
||||||
@ -148,19 +171,21 @@ mod test {
|
|||||||
vp.prefer_dependency(dep("foo", "=1.2.3"));
|
vp.prefer_dependency(dep("foo", "=1.2.3"));
|
||||||
|
|
||||||
let mut summaries = vec![
|
let mut summaries = vec![
|
||||||
summ("foo", "1.2.4"),
|
summ("foo", "1.2.4", None),
|
||||||
summ("foo", "1.2.3"),
|
summ("foo", "1.2.3", None),
|
||||||
summ("foo", "1.1.0"),
|
summ("foo", "1.1.0", None),
|
||||||
summ("foo", "1.0.9"),
|
summ("foo", "1.0.9", None),
|
||||||
];
|
];
|
||||||
|
|
||||||
vp.sort_summaries(&mut summaries, VersionOrdering::MaximumVersionsFirst, false);
|
vp.version_ordering(VersionOrdering::MaximumVersionsFirst);
|
||||||
|
vp.sort_summaries(&mut summaries, None);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
describe(&summaries),
|
describe(&summaries),
|
||||||
"foo/1.2.3, foo/1.2.4, foo/1.1.0, foo/1.0.9".to_string()
|
"foo/1.2.3, foo/1.2.4, foo/1.1.0, foo/1.0.9".to_string()
|
||||||
);
|
);
|
||||||
|
|
||||||
vp.sort_summaries(&mut summaries, VersionOrdering::MinimumVersionsFirst, false);
|
vp.version_ordering(VersionOrdering::MinimumVersionsFirst);
|
||||||
|
vp.sort_summaries(&mut summaries, None);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
describe(&summaries),
|
describe(&summaries),
|
||||||
"foo/1.2.3, foo/1.0.9, foo/1.1.0, foo/1.2.4".to_string()
|
"foo/1.2.3, foo/1.0.9, foo/1.1.0, foo/1.2.4".to_string()
|
||||||
@ -174,22 +199,51 @@ mod test {
|
|||||||
vp.prefer_dependency(dep("foo", "=1.1.0"));
|
vp.prefer_dependency(dep("foo", "=1.1.0"));
|
||||||
|
|
||||||
let mut summaries = vec![
|
let mut summaries = vec![
|
||||||
summ("foo", "1.2.4"),
|
summ("foo", "1.2.4", None),
|
||||||
summ("foo", "1.2.3"),
|
summ("foo", "1.2.3", None),
|
||||||
summ("foo", "1.1.0"),
|
summ("foo", "1.1.0", None),
|
||||||
summ("foo", "1.0.9"),
|
summ("foo", "1.0.9", None),
|
||||||
];
|
];
|
||||||
|
|
||||||
vp.sort_summaries(&mut summaries, VersionOrdering::MaximumVersionsFirst, false);
|
vp.version_ordering(VersionOrdering::MaximumVersionsFirst);
|
||||||
|
vp.sort_summaries(&mut summaries, None);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
describe(&summaries),
|
describe(&summaries),
|
||||||
"foo/1.2.3, foo/1.1.0, foo/1.2.4, foo/1.0.9".to_string()
|
"foo/1.2.3, foo/1.1.0, foo/1.2.4, foo/1.0.9".to_string()
|
||||||
);
|
);
|
||||||
|
|
||||||
vp.sort_summaries(&mut summaries, VersionOrdering::MinimumVersionsFirst, false);
|
vp.version_ordering(VersionOrdering::MinimumVersionsFirst);
|
||||||
|
vp.sort_summaries(&mut summaries, None);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
describe(&summaries),
|
describe(&summaries),
|
||||||
"foo/1.1.0, foo/1.2.3, foo/1.0.9, foo/1.2.4".to_string()
|
"foo/1.1.0, foo/1.2.3, foo/1.0.9, foo/1.2.4".to_string()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_max_rust_version() {
|
||||||
|
let mut vp = VersionPreferences::default();
|
||||||
|
vp.max_rust_version(Some("1.50".parse().unwrap()));
|
||||||
|
|
||||||
|
let mut summaries = vec![
|
||||||
|
summ("foo", "1.2.4", Some("1.60")),
|
||||||
|
summ("foo", "1.2.3", Some("1.50")),
|
||||||
|
summ("foo", "1.1.0", Some("1.40")),
|
||||||
|
summ("foo", "1.0.9", None),
|
||||||
|
];
|
||||||
|
|
||||||
|
vp.version_ordering(VersionOrdering::MaximumVersionsFirst);
|
||||||
|
vp.sort_summaries(&mut summaries, None);
|
||||||
|
assert_eq!(
|
||||||
|
describe(&summaries),
|
||||||
|
"foo/1.2.3, foo/1.1.0, foo/1.0.9".to_string()
|
||||||
|
);
|
||||||
|
|
||||||
|
vp.version_ordering(VersionOrdering::MinimumVersionsFirst);
|
||||||
|
vp.sort_summaries(&mut summaries, None);
|
||||||
|
assert_eq!(
|
||||||
|
describe(&summaries),
|
||||||
|
"foo/1.0.9, foo/1.1.0, foo/1.2.3".to_string()
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,7 @@ use crate::core::resolver::features::{
|
|||||||
CliFeatures, FeatureOpts, FeatureResolver, ForceAllTargets, RequestedFeatures, ResolvedFeatures,
|
CliFeatures, FeatureOpts, FeatureResolver, ForceAllTargets, RequestedFeatures, ResolvedFeatures,
|
||||||
};
|
};
|
||||||
use crate::core::resolver::{
|
use crate::core::resolver::{
|
||||||
self, HasDevUnits, Resolve, ResolveOpts, ResolveVersion, VersionPreferences,
|
self, HasDevUnits, Resolve, ResolveOpts, ResolveVersion, VersionOrdering, VersionPreferences,
|
||||||
};
|
};
|
||||||
use crate::core::summary::Summary;
|
use crate::core::summary::Summary;
|
||||||
use crate::core::Feature;
|
use crate::core::Feature;
|
||||||
@ -321,6 +321,12 @@ pub fn resolve_with_previous<'cfg>(
|
|||||||
// While registering patches, we will record preferences for particular versions
|
// While registering patches, we will record preferences for particular versions
|
||||||
// of various packages.
|
// of various packages.
|
||||||
let mut version_prefs = VersionPreferences::default();
|
let mut version_prefs = VersionPreferences::default();
|
||||||
|
if ws.config().cli_unstable().minimal_versions {
|
||||||
|
version_prefs.version_ordering(VersionOrdering::MinimumVersionsFirst)
|
||||||
|
}
|
||||||
|
if ws.config().cli_unstable().msrv_policy {
|
||||||
|
version_prefs.max_rust_version(max_rust_version.cloned());
|
||||||
|
}
|
||||||
|
|
||||||
// This is a set of PackageIds of `[patch]` entries, and some related locked PackageIds, for
|
// This is a set of PackageIds of `[patch]` entries, and some related locked PackageIds, for
|
||||||
// which locking should be avoided (but which will be preferred when searching dependencies,
|
// which locking should be avoided (but which will be preferred when searching dependencies,
|
||||||
@ -509,7 +515,6 @@ pub fn resolve_with_previous<'cfg>(
|
|||||||
ws.unstable_features()
|
ws.unstable_features()
|
||||||
.require(Feature::public_dependency())
|
.require(Feature::public_dependency())
|
||||||
.is_ok(),
|
.is_ok(),
|
||||||
max_rust_version,
|
|
||||||
)?;
|
)?;
|
||||||
let patches: Vec<_> = registry
|
let patches: Vec<_> = registry
|
||||||
.patches()
|
.patches()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user