Skip to content

Commit

Permalink
Respect MSRV during resolution
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
est31 committed Jan 23, 2019
1 parent 1c087ee commit 6ce9b61
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 5 deletions.
9 changes: 7 additions & 2 deletions src/cargo/sources/registry/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
56 changes: 53 additions & 3 deletions src/cargo/sources/registry/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<Version>,
}

fn get_local_msrv(config: &Config) -> Option<Version> {
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<HashMap<(String, Version), Version>> {
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<MsrvInfo> = serde_json::from_str(&msrv_infos_str).ok()?;
let msrv_infos = msrv_infos.into_iter()
.map(|MsrvInfo { name, vers, msrv }| ((name, vers), msrv))
.collect::<HashMap<(String, Version), Version>>();

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<dyn RegistryData + 'cfg>,
msrv_infos: MsrvInfos,
index: index::RegistryIndex<'cfg>,
index_locked: bool,
}
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand All @@ -519,15 +569,15 @@ 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);
}
})
}

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 {
Expand Down

0 comments on commit 6ce9b61

Please sign in to comment.