Skip to content

Commit 6ce9b61

Browse files
committed
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.
1 parent 1c087ee commit 6ce9b61

File tree

2 files changed

+60
-5
lines changed

2 files changed

+60
-5
lines changed

src/cargo/sources/registry/index.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use semver::Version;
88
use crate::core::dependency::Dependency;
99
use crate::core::{PackageId, SourceId, Summary};
1010
use crate::sources::registry::RegistryData;
11-
use crate::sources::registry::{RegistryPackage, INDEX_LOCK};
11+
use crate::sources::registry::{RegistryPackage, INDEX_LOCK, MsrvInfos};
1212
use crate::util::{internal, CargoResult, Config, Filesystem, ToSemver};
1313

1414
/// Crates.io treats hyphen and underscores as interchangeable
@@ -273,15 +273,20 @@ impl<'cfg> RegistryIndex<'cfg> {
273273
&mut self,
274274
dep: &Dependency,
275275
load: &mut dyn RegistryData,
276+
msrv_infos: &mut MsrvInfos,
276277
f: &mut dyn FnMut(Summary),
277278
) -> CargoResult<()> {
278279
let source_id = self.source_id;
279280
let name = dep.package_name().as_str();
280281
let ignore_yanked = self.config.ignore_yanked();
282+
let local_msrv = msrv_infos.local_msrv();
281283
let summaries = self.summaries(name, load)?;
282284
let summaries = summaries
283285
.iter()
284-
.filter(|&&(_, yanked)| dep.source_id().precise().is_some() || !yanked || ignore_yanked)
286+
.filter(|&(summary, yanked)| {
287+
let msrv_info = msrv_infos.get(&summary.package_id().name(), summary.package_id().version());
288+
dep.source_id().precise().is_some() || ((!yanked || ignore_yanked) && local_msrv >= msrv_info)
289+
})
285290
.map(|s| s.0.clone());
286291

287292
// Handle `cargo update --precise` here. If specified, our own source

src/cargo/sources/registry/mod.rs

+53-3
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ use std::borrow::Cow;
162162
use std::collections::BTreeMap;
163163
use std::fs::File;
164164
use std::path::{Path, PathBuf};
165+
use std::collections::HashMap;
165166

166167
use flate2::read::GzDecoder;
167168
use log::debug;
@@ -184,12 +185,60 @@ pub const CRATES_IO_REGISTRY: &str = "crates-io";
184185
const CRATE_TEMPLATE: &str = "{crate}";
185186
const VERSION_TEMPLATE: &str = "{version}";
186187

188+
pub struct MsrvInfos {
189+
msrv_infos: HashMap<(String, Version), Version>,
190+
local_msrv: Option<Version>,
191+
}
192+
193+
fn get_local_msrv(config: &Config) -> Option<Version> {
194+
let values = config.values().ok()?;
195+
let msrv = values.get("msrv")?;
196+
let msrv_str = msrv.string("").ok()?.0;
197+
Version::parse(msrv_str).ok()
198+
}
199+
fn get_msrv_infos(config: &Config) -> Option<HashMap<(String, Version), Version>> {
200+
let values = config.values().ok()?;
201+
let path_value = values.get("msrv_infos")?;
202+
let path = path_value.string("").ok()?.0;
203+
let msrv_infos_str = std::fs::read_to_string(path).ok()?;
204+
#[derive(Deserialize)]
205+
struct MsrvInfo {
206+
name: String,
207+
vers: Version,
208+
msrv: Version,
209+
}
210+
let msrv_infos: Vec<MsrvInfo> = serde_json::from_str(&msrv_infos_str).ok()?;
211+
let msrv_infos = msrv_infos.into_iter()
212+
.map(|MsrvInfo { name, vers, msrv }| ((name, vers), msrv))
213+
.collect::<HashMap<(String, Version), Version>>();
214+
215+
Some(msrv_infos)
216+
}
217+
218+
impl MsrvInfos {
219+
pub fn new(config: &Config) -> Self {
220+
Self {
221+
msrv_infos: get_msrv_infos(config).unwrap_or_else(HashMap::new),
222+
local_msrv: get_local_msrv(config),
223+
}
224+
}
225+
226+
fn get(&self, name: &str, v: &Version) -> Option<&Version> {
227+
self.msrv_infos.get(&(name.to_string(), v.clone()))
228+
}
229+
/// Obtains the msrv used for resolution
230+
fn local_msrv(&self) -> Option<&Version> {
231+
self.local_msrv.as_ref()
232+
}
233+
}
234+
187235
pub struct RegistrySource<'cfg> {
188236
source_id: SourceId,
189237
src_path: Filesystem,
190238
config: &'cfg Config,
191239
updated: bool,
192240
ops: Box<dyn RegistryData + 'cfg>,
241+
msrv_infos: MsrvInfos,
193242
index: index::RegistryIndex<'cfg>,
194243
index_locked: bool,
195244
}
@@ -408,6 +457,7 @@ impl<'cfg> RegistrySource<'cfg> {
408457
config,
409458
source_id,
410459
updated: false,
460+
msrv_infos: MsrvInfos::new(config),
411461
index: index::RegistryIndex::new(source_id, ops.index_path(), config, index_locked),
412462
index_locked,
413463
ops,
@@ -505,7 +555,7 @@ impl<'cfg> Source for RegistrySource<'cfg> {
505555
if dep.source_id().precise().is_some() && !self.updated {
506556
debug!("attempting query without update");
507557
let mut called = false;
508-
self.index.query_inner(dep, &mut *self.ops, &mut |s| {
558+
self.index.query_inner(dep, &mut *self.ops, &mut self.msrv_infos, &mut |s| {
509559
if dep.matches(&s) {
510560
called = true;
511561
f(s);
@@ -519,15 +569,15 @@ impl<'cfg> Source for RegistrySource<'cfg> {
519569
}
520570
}
521571

522-
self.index.query_inner(dep, &mut *self.ops, &mut |s| {
572+
self.index.query_inner(dep, &mut *self.ops, &mut self.msrv_infos, &mut |s| {
523573
if dep.matches(&s) {
524574
f(s);
525575
}
526576
})
527577
}
528578

529579
fn fuzzy_query(&mut self, dep: &Dependency, f: &mut dyn FnMut(Summary)) -> CargoResult<()> {
530-
self.index.query_inner(dep, &mut *self.ops, f)
580+
self.index.query_inner(dep, &mut *self.ops, &mut self.msrv_infos, f)
531581
}
532582

533583
fn supports_checksums(&self) -> bool {

0 commit comments

Comments
 (0)