@@ -75,11 +75,13 @@ use crate::core::compiler::future_incompat::{
75
75
FutureBreakageItem , FutureIncompatReportPackage , OnDiskReports ,
76
76
} ;
77
77
use crate :: core:: resolver:: ResolveBehavior ;
78
+ use crate :: core:: { Dependency , Workspace } ;
78
79
use crate :: core:: { PackageId , Shell , TargetKind } ;
80
+ use crate :: sources:: SourceConfigMap ;
79
81
use crate :: util:: diagnostic_server:: { self , DiagnosticPrinter } ;
80
82
use crate :: util:: machine_message:: { self , Message as _} ;
81
83
use crate :: util:: CargoResult ;
82
- use crate :: util:: { self , internal, profile} ;
84
+ use crate :: util:: { self , internal, iter_join , profile} ;
83
85
use crate :: util:: { Config , DependencyQueue , Progress , ProgressStyle , Queue } ;
84
86
85
87
/// This structure is backed by the `DependencyQueue` type and manages the
@@ -911,15 +913,12 @@ impl<'cfg> DrainState<'cfg> {
911
913
}
912
914
913
915
// Get a list of unique and sorted package name/versions.
914
- let package_vers : BTreeSet < _ > = self
916
+ let package_ids : BTreeSet < _ > = self
915
917
. per_package_future_incompat_reports
916
918
. iter ( )
917
919
. map ( |r| r. package_id )
918
920
. collect ( ) ;
919
- let package_vers: Vec < _ > = package_vers
920
- . into_iter ( )
921
- . map ( |pid| pid. to_string ( ) )
922
- . collect ( ) ;
921
+ let package_vers: Vec < _ > = package_ids. iter ( ) . map ( |pid| pid. to_string ( ) ) . collect ( ) ;
923
922
924
923
if should_display_message || bcx. build_config . future_incompat_report {
925
924
drop ( bcx. config . shell ( ) . warn ( & format ! (
@@ -934,8 +933,76 @@ impl<'cfg> DrainState<'cfg> {
934
933
let report_id = on_disk_reports. last_id ( ) ;
935
934
936
935
if bcx. build_config . future_incompat_report {
937
- let rendered = on_disk_reports. get_report ( report_id, bcx. config ) . unwrap ( ) ;
938
- drop ( bcx. config . shell ( ) . print_ansi_stderr ( rendered. as_bytes ( ) ) ) ;
936
+ let upstream_info = package_ids
937
+ . iter ( )
938
+ . map ( |package_id| {
939
+ let manifest = bcx. packages . get_one ( * package_id) . unwrap ( ) . manifest ( ) ;
940
+ format ! (
941
+ "
942
+ - {name}
943
+ - Repository: {url}
944
+ - Detailed warning command: `cargo report future-incompatibilities --id {id} --crate '{name}'" ,
945
+ name = package_id,
946
+ url = manifest
947
+ . metadata( )
948
+ . repository
949
+ . as_deref( )
950
+ . unwrap_or( "<not found>" ) ,
951
+ id = report_id,
952
+ )
953
+ } )
954
+ . collect :: < Vec < _ > > ( )
955
+ . join ( "\n " ) ;
956
+
957
+ let ( compat, incompat) =
958
+ get_updates ( bcx. ws , & package_ids) . unwrap_or ( ( String :: new ( ) , String :: new ( ) ) ) ;
959
+
960
+ let compat_message = if !compat. is_empty ( ) {
961
+ format ! (
962
+ "
963
+ - Some affected dependencies have minor or patch version updates available:
964
+ {compat}" ,
965
+ compat = compat
966
+ )
967
+ } else {
968
+ String :: new ( )
969
+ } ;
970
+
971
+ let incompat_message = if !incompat. is_empty ( ) {
972
+ format ! (
973
+ "
974
+ - If a minor dependency update does not help, you can try updating to a new
975
+ major version of those dependencies. You have to do this manually:
976
+ {incompat}
977
+ " ,
978
+ incompat = incompat
979
+ )
980
+ } else {
981
+ String :: new ( )
982
+ } ;
983
+
984
+ drop ( bcx. config . shell ( ) . note ( & format ! (
985
+ "
986
+ To solve this problem, you can try the following approaches:
987
+
988
+ {compat_message}
989
+ {incompat_message}
990
+ - If the issue is not solved by updating the dependencies, a fix has to be
991
+ implemented by those dependencies. You can help with that by notifying the
992
+ maintainers of this problem (e.g. by creating a bug report) or by proposing a
993
+ fix to the maintainers (e.g. by creating a pull request):
994
+ {upstream_info}
995
+
996
+ - If waiting for an upstream fix is not an option, you can use the `[patch]`
997
+ section in `Cargo.toml` to use your own version of the dependency. For more
998
+ information, see:
999
+ https://doc.rust-lang.org/cargo/reference/overriding-dependencies.html#the-patch-section
1000
+ " ,
1001
+ upstream_info = upstream_info,
1002
+ compat_message = compat_message,
1003
+ incompat_message = incompat_message
1004
+ ) ) ) ;
1005
+
939
1006
drop ( bcx. config . shell ( ) . note ( & format ! (
940
1007
"this report can be shown with `cargo report \
941
1008
future-incompatibilities -Z future-incompat-report --id {}`",
@@ -1283,3 +1350,75 @@ feature resolver. Try updating to diesel 1.4.8 to fix this error.
1283
1350
Ok ( ( ) )
1284
1351
}
1285
1352
}
1353
+
1354
+ // Returns a pair (compatible_updates, incompatible_updates),
1355
+ // of semver-compatible and semver-incompatible update versions,
1356
+ // respectively.
1357
+ fn get_updates ( ws : & Workspace < ' _ > , package_ids : & BTreeSet < PackageId > ) -> Option < ( String , String ) > {
1358
+ // This in general ignores all errors since this is opportunistic.
1359
+ let _lock = ws. config ( ) . acquire_package_cache_lock ( ) . ok ( ) ?;
1360
+ // Create a set of updated registry sources.
1361
+ let map = SourceConfigMap :: new ( ws. config ( ) ) . ok ( ) ?;
1362
+ let package_ids: BTreeSet < _ > = package_ids
1363
+ . iter ( )
1364
+ . filter ( |pkg_id| pkg_id. source_id ( ) . is_registry ( ) )
1365
+ . collect ( ) ;
1366
+ let source_ids: HashSet < _ > = package_ids
1367
+ . iter ( )
1368
+ . map ( |pkg_id| pkg_id. source_id ( ) )
1369
+ . collect ( ) ;
1370
+ let mut sources: HashMap < _ , _ > = source_ids
1371
+ . into_iter ( )
1372
+ . filter_map ( |sid| {
1373
+ let source = map. load ( sid, & HashSet :: new ( ) ) . ok ( ) ?;
1374
+ Some ( ( sid, source) )
1375
+ } )
1376
+ . collect ( ) ;
1377
+ // Query the sources for new versions.
1378
+ let mut compatible = String :: new ( ) ;
1379
+ let mut incompatible = String :: new ( ) ;
1380
+ for pkg_id in package_ids {
1381
+ let source = match sources. get_mut ( & pkg_id. source_id ( ) ) {
1382
+ Some ( s) => s,
1383
+ None => continue ,
1384
+ } ;
1385
+ let dep = Dependency :: parse ( pkg_id. name ( ) , None , pkg_id. source_id ( ) ) . ok ( ) ?;
1386
+ let summaries = source. query_vec ( & dep) . ok ( ) ?;
1387
+ let ( mut compatible_versions, mut incompatible_versions) : ( Vec < _ > , Vec < _ > ) = summaries
1388
+ . iter ( )
1389
+ . map ( |summary| summary. version ( ) )
1390
+ . filter ( |version| * version > pkg_id. version ( ) )
1391
+ . partition ( |version| version. major == pkg_id. version ( ) . major ) ;
1392
+ compatible_versions. sort ( ) ;
1393
+ incompatible_versions. sort ( ) ;
1394
+
1395
+ let compatible_versions = compatible_versions
1396
+ . into_iter ( )
1397
+ . map ( |version| version. to_string ( ) ) ;
1398
+ let compatible_versions = iter_join ( compatible_versions, ", " ) ;
1399
+
1400
+ let incompatible_versions = incompatible_versions
1401
+ . into_iter ( )
1402
+ . map ( |version| version. to_string ( ) ) ;
1403
+ let incompatible_versions = iter_join ( incompatible_versions, ", " ) ;
1404
+
1405
+ if !compatible_versions. is_empty ( ) {
1406
+ writeln ! (
1407
+ compatible,
1408
+ "{} has the following newer versions available: {}" ,
1409
+ pkg_id, compatible_versions
1410
+ )
1411
+ . unwrap ( ) ;
1412
+ }
1413
+
1414
+ if !incompatible_versions. is_empty ( ) {
1415
+ writeln ! (
1416
+ incompatible,
1417
+ "{} has the following newer versions available: {}" ,
1418
+ pkg_id, incompatible_versions
1419
+ )
1420
+ . unwrap ( ) ;
1421
+ }
1422
+ }
1423
+ Some ( ( compatible, incompatible) )
1424
+ }
0 commit comments