From 6ce9b611903b9be85cc6ad76a8eea09f7767d22b Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 23 Jan 2019 03:57:49 +0100 Subject: [PATCH] Respect MSRV during resolution This commit alows you to specify the MSRV in .cargo/config via the msrv key, and via the msrv_infos key you can set the path of a msrv information file. If the local msrv is below the msrv of a given crate, it's not being included for resolution. --- src/cargo/sources/registry/index.rs | 9 +++-- src/cargo/sources/registry/mod.rs | 56 +++++++++++++++++++++++++++-- 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/src/cargo/sources/registry/index.rs b/src/cargo/sources/registry/index.rs index 03de78f4813..0d7090578d5 100644 --- a/src/cargo/sources/registry/index.rs +++ b/src/cargo/sources/registry/index.rs @@ -8,7 +8,7 @@ use semver::Version; use crate::core::dependency::Dependency; use crate::core::{PackageId, SourceId, Summary}; use crate::sources::registry::RegistryData; -use crate::sources::registry::{RegistryPackage, INDEX_LOCK}; +use crate::sources::registry::{RegistryPackage, INDEX_LOCK, MsrvInfos}; use crate::util::{internal, CargoResult, Config, Filesystem, ToSemver}; /// Crates.io treats hyphen and underscores as interchangeable @@ -273,15 +273,20 @@ impl<'cfg> RegistryIndex<'cfg> { &mut self, dep: &Dependency, load: &mut dyn RegistryData, + msrv_infos: &mut MsrvInfos, f: &mut dyn FnMut(Summary), ) -> CargoResult<()> { let source_id = self.source_id; let name = dep.package_name().as_str(); let ignore_yanked = self.config.ignore_yanked(); + let local_msrv = msrv_infos.local_msrv(); let summaries = self.summaries(name, load)?; let summaries = summaries .iter() - .filter(|&&(_, yanked)| dep.source_id().precise().is_some() || !yanked || ignore_yanked) + .filter(|&(summary, yanked)| { + let msrv_info = msrv_infos.get(&summary.package_id().name(), summary.package_id().version()); + dep.source_id().precise().is_some() || ((!yanked || ignore_yanked) && local_msrv >= msrv_info) + }) .map(|s| s.0.clone()); // Handle `cargo update --precise` here. If specified, our own source diff --git a/src/cargo/sources/registry/mod.rs b/src/cargo/sources/registry/mod.rs index e2f756aeec0..1dffd75b9f1 100644 --- a/src/cargo/sources/registry/mod.rs +++ b/src/cargo/sources/registry/mod.rs @@ -162,6 +162,7 @@ use std::borrow::Cow; use std::collections::BTreeMap; use std::fs::File; use std::path::{Path, PathBuf}; +use std::collections::HashMap; use flate2::read::GzDecoder; use log::debug; @@ -184,12 +185,60 @@ pub const CRATES_IO_REGISTRY: &str = "crates-io"; const CRATE_TEMPLATE: &str = "{crate}"; const VERSION_TEMPLATE: &str = "{version}"; +pub struct MsrvInfos { + msrv_infos: HashMap<(String, Version), Version>, + local_msrv: Option, +} + +fn get_local_msrv(config: &Config) -> Option { + let values = config.values().ok()?; + let msrv = values.get("msrv")?; + let msrv_str = msrv.string("").ok()?.0; + Version::parse(msrv_str).ok() +} +fn get_msrv_infos(config: &Config) -> Option> { + let values = config.values().ok()?; + let path_value = values.get("msrv_infos")?; + let path = path_value.string("").ok()?.0; + let msrv_infos_str = std::fs::read_to_string(path).ok()?; + #[derive(Deserialize)] + struct MsrvInfo { + name: String, + vers: Version, + msrv: Version, + } + let msrv_infos: Vec = serde_json::from_str(&msrv_infos_str).ok()?; + let msrv_infos = msrv_infos.into_iter() + .map(|MsrvInfo { name, vers, msrv }| ((name, vers), msrv)) + .collect::>(); + + Some(msrv_infos) +} + +impl MsrvInfos { + pub fn new(config: &Config) -> Self { + Self { + msrv_infos: get_msrv_infos(config).unwrap_or_else(HashMap::new), + local_msrv: get_local_msrv(config), + } + } + + fn get(&self, name: &str, v: &Version) -> Option<&Version> { + self.msrv_infos.get(&(name.to_string(), v.clone())) + } + /// Obtains the msrv used for resolution + fn local_msrv(&self) -> Option<&Version> { + self.local_msrv.as_ref() + } +} + pub struct RegistrySource<'cfg> { source_id: SourceId, src_path: Filesystem, config: &'cfg Config, updated: bool, ops: Box, + msrv_infos: MsrvInfos, index: index::RegistryIndex<'cfg>, index_locked: bool, } @@ -408,6 +457,7 @@ impl<'cfg> RegistrySource<'cfg> { config, source_id, updated: false, + msrv_infos: MsrvInfos::new(config), index: index::RegistryIndex::new(source_id, ops.index_path(), config, index_locked), index_locked, ops, @@ -505,7 +555,7 @@ impl<'cfg> Source for RegistrySource<'cfg> { if dep.source_id().precise().is_some() && !self.updated { debug!("attempting query without update"); let mut called = false; - self.index.query_inner(dep, &mut *self.ops, &mut |s| { + self.index.query_inner(dep, &mut *self.ops, &mut self.msrv_infos, &mut |s| { if dep.matches(&s) { called = true; f(s); @@ -519,7 +569,7 @@ impl<'cfg> Source for RegistrySource<'cfg> { } } - self.index.query_inner(dep, &mut *self.ops, &mut |s| { + self.index.query_inner(dep, &mut *self.ops, &mut self.msrv_infos, &mut |s| { if dep.matches(&s) { f(s); } @@ -527,7 +577,7 @@ impl<'cfg> Source for RegistrySource<'cfg> { } fn fuzzy_query(&mut self, dep: &Dependency, f: &mut dyn FnMut(Summary)) -> CargoResult<()> { - self.index.query_inner(dep, &mut *self.ops, f) + self.index.query_inner(dep, &mut *self.ops, &mut self.msrv_infos, f) } fn supports_checksums(&self) -> bool {