Skip to content

Commit f57be6f

Browse files
committed
Adjust message and move code to future_incompat module
1 parent 6f18507 commit f57be6f

File tree

2 files changed

+193
-186
lines changed

2 files changed

+193
-186
lines changed

src/cargo/core/compiler/future_incompat.rs

Lines changed: 189 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
//! Support for future-incompatible warning reporting.
22
3-
use crate::core::{PackageId, Workspace};
3+
use crate::core::compiler::BuildContext;
4+
use crate::core::{Dependency, PackageId, Workspace};
5+
use crate::sources::SourceConfigMap;
46
use crate::util::{iter_join, CargoResult, Config};
57
use anyhow::{bail, format_err, Context};
68
use serde::{Deserialize, Serialize};
7-
use std::collections::BTreeMap;
9+
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
10+
use std::fmt::Write as _;
811
use std::io::{Read, Write};
912

1013
pub const REPORT_PREAMBLE: &str = "\
@@ -208,7 +211,7 @@ impl OnDiskReports {
208211
format_err!(
209212
"could not find package with ID `{}`\n
210213
Available packages are: {}\n
211-
Omit the `--crate` flag to display a report for all crates",
214+
Omit the `--package` flag to display a report for all packages",
212215
package,
213216
iter_join(report.per_package.keys(), ", ")
214217
)
@@ -260,3 +263,186 @@ fn render_report(per_package_reports: &[FutureIncompatReportPackage]) -> BTreeMa
260263
}
261264
report
262265
}
266+
267+
// Returns a pair (compatible_updates, incompatible_updates),
268+
// of semver-compatible and semver-incompatible update versions,
269+
// respectively.
270+
fn get_updates(ws: &Workspace<'_>, package_ids: &BTreeSet<PackageId>) -> Option<String> {
271+
// This in general ignores all errors since this is opportunistic.
272+
let _lock = ws.config().acquire_package_cache_lock().ok()?;
273+
// Create a set of updated registry sources.
274+
let map = SourceConfigMap::new(ws.config()).ok()?;
275+
let package_ids: BTreeSet<_> = package_ids
276+
.iter()
277+
.filter(|pkg_id| pkg_id.source_id().is_registry())
278+
.collect();
279+
let source_ids: HashSet<_> = package_ids
280+
.iter()
281+
.map(|pkg_id| pkg_id.source_id())
282+
.collect();
283+
let mut sources: HashMap<_, _> = source_ids
284+
.into_iter()
285+
.filter_map(|sid| {
286+
let source = map.load(sid, &HashSet::new()).ok()?;
287+
Some((sid, source))
288+
})
289+
.collect();
290+
// Query the sources for new versions.
291+
let mut updates = String::new();
292+
for pkg_id in package_ids {
293+
let source = match sources.get_mut(&pkg_id.source_id()) {
294+
Some(s) => s,
295+
None => continue,
296+
};
297+
let dep = Dependency::parse(pkg_id.name(), None, pkg_id.source_id()).ok()?;
298+
let summaries = source.query_vec(&dep).ok()?;
299+
let mut updated_versions: Vec<_> = summaries
300+
.iter()
301+
.map(|summary| summary.version())
302+
.filter(|version| *version > pkg_id.version())
303+
.collect();
304+
updated_versions.sort();
305+
306+
let updated_versions = iter_join(
307+
updated_versions
308+
.into_iter()
309+
.map(|version| version.to_string()),
310+
", ",
311+
);
312+
313+
if !updated_versions.is_empty() {
314+
writeln!(
315+
updates,
316+
"{} has the following newer versions available: {}",
317+
pkg_id, updated_versions
318+
)
319+
.unwrap();
320+
}
321+
}
322+
Some(updates)
323+
}
324+
325+
pub fn render_message(
326+
bcx: &BuildContext<'_, '_>,
327+
per_package_future_incompat_reports: &[FutureIncompatReportPackage],
328+
) {
329+
if !bcx.config.cli_unstable().future_incompat_report {
330+
return;
331+
}
332+
let should_display_message = match bcx.config.future_incompat_config() {
333+
Ok(config) => config.should_display_message(),
334+
Err(e) => {
335+
crate::display_warning_with_error(
336+
"failed to read future-incompat config from disk",
337+
&e,
338+
&mut bcx.config.shell(),
339+
);
340+
true
341+
}
342+
};
343+
344+
if per_package_future_incompat_reports.is_empty() {
345+
// Explicitly passing a command-line flag overrides
346+
// `should_display_message` from the config file
347+
if bcx.build_config.future_incompat_report {
348+
drop(
349+
bcx.config
350+
.shell()
351+
.note("0 dependencies had future-incompatible warnings"),
352+
);
353+
}
354+
return;
355+
}
356+
357+
// Get a list of unique and sorted package name/versions.
358+
let package_ids: BTreeSet<_> = per_package_future_incompat_reports
359+
.iter()
360+
.map(|r| r.package_id)
361+
.collect();
362+
let package_vers: Vec<_> = package_ids.iter().map(|pid| pid.to_string()).collect();
363+
364+
if should_display_message || bcx.build_config.future_incompat_report {
365+
drop(bcx.config.shell().warn(&format!(
366+
"the following packages contain code that will be rejected by a future \
367+
version of Rust: {}",
368+
package_vers.join(", ")
369+
)));
370+
}
371+
372+
let updated_versions = get_updates(bcx.ws, &package_ids).unwrap_or(String::new());
373+
374+
let update_message = if !updated_versions.is_empty() {
375+
format!(
376+
"
377+
- Some affected dependencies have newer versions available.
378+
You may want to consider updating them to a newer version to see if the issue has been fixed.
379+
380+
{updated_versions}\n",
381+
updated_versions = updated_versions
382+
)
383+
} else {
384+
String::new()
385+
};
386+
387+
let on_disk_reports = OnDiskReports::save_report(
388+
bcx.ws,
389+
update_message.clone(),
390+
per_package_future_incompat_reports,
391+
);
392+
let report_id = on_disk_reports.last_id();
393+
394+
if bcx.build_config.future_incompat_report {
395+
let upstream_info = package_ids
396+
.iter()
397+
.map(|package_id| {
398+
let manifest = bcx.packages.get_one(*package_id).unwrap().manifest();
399+
format!(
400+
"
401+
- {name}
402+
- Repository: {url}
403+
- Detailed warning command: `cargo report future-incompatibilities --id {id} --crate \"{name}\"",
404+
name = format!("{}:{}", package_id.name(), package_id.version()),
405+
url = manifest
406+
.metadata()
407+
.repository
408+
.as_deref()
409+
.unwrap_or("<not found>"),
410+
id = report_id,
411+
)
412+
})
413+
.collect::<Vec<_>>()
414+
.join("\n");
415+
drop(bcx.config.shell().note(&format!(
416+
"
417+
To solve this problem, you can try the following approaches:
418+
419+
{update_message}
420+
- If the issue is not solved by updating the dependencies, a fix has to be
421+
implemented by those dependencies. You can help with that by notifying the
422+
maintainers of this problem (e.g. by creating a bug report) or by proposing a
423+
fix to the maintainers (e.g. by creating a pull request):
424+
{upstream_info}
425+
426+
- If waiting for an upstream fix is not an option, you can use the `[patch]`
427+
section in `Cargo.toml` to use your own version of the dependency. For more
428+
information, see:
429+
https://doc.rust-lang.org/cargo/reference/overriding-dependencies.html#the-patch-section
430+
",
431+
upstream_info = upstream_info,
432+
update_message = update_message,
433+
)));
434+
435+
drop(bcx.config.shell().note(&format!(
436+
"this report can be shown with `cargo report \
437+
future-incompatibilities -Z future-incompat-report --id {}`",
438+
report_id
439+
)));
440+
} else if should_display_message {
441+
drop(bcx.config.shell().note(&format!(
442+
"to see what the problems were, use the option \
443+
`--future-incompat-report`, or run `cargo report \
444+
future-incompatibilities --id {}`",
445+
report_id
446+
)));
447+
}
448+
}

0 commit comments

Comments
 (0)