Make cargo metadata output deterministic

Uses BTreeMap instead of HashMap for the `cargo metadata` command.
The change did not cause a measurable performance impact for
running `cargo metadata` on `cargo` itself.

Fixes #8477
This commit is contained in:
Arlo Siemsen 2020-07-15 10:43:34 -07:00
parent 2f4097aa6b
commit 18ff915c8a

View file

@ -6,7 +6,7 @@ use crate::ops::{self, Packages};
use crate::util::CargoResult; use crate::util::CargoResult;
use cargo_platform::Platform; use cargo_platform::Platform;
use serde::Serialize; use serde::Serialize;
use std::collections::HashMap; use std::collections::BTreeMap;
use std::path::PathBuf; use std::path::PathBuf;
const VERSION: u32 = 1; const VERSION: u32 = 1;
@ -130,7 +130,7 @@ fn build_resolve_graph(
// Download all Packages. This is needed to serialize the information // Download all Packages. This is needed to serialize the information
// for every package. In theory this could honor target filtering, // for every package. In theory this could honor target filtering,
// but that would be somewhat complex. // but that would be somewhat complex.
let mut package_map: HashMap<PackageId, Package> = ws_resolve let package_map: BTreeMap<PackageId, Package> = ws_resolve
.pkg_set .pkg_set
.get_many(ws_resolve.pkg_set.package_ids())? .get_many(ws_resolve.pkg_set.package_ids())?
.into_iter() .into_iter()
@ -140,7 +140,7 @@ fn build_resolve_graph(
// Start from the workspace roots, and recurse through filling out the // Start from the workspace roots, and recurse through filling out the
// map, filtering targets as necessary. // map, filtering targets as necessary.
let mut node_map = HashMap::new(); let mut node_map = BTreeMap::new();
for member_pkg in ws.members() { for member_pkg in ws.members() {
build_resolve_graph_r( build_resolve_graph_r(
&mut node_map, &mut node_map,
@ -153,21 +153,22 @@ fn build_resolve_graph(
} }
// Get a Vec of Packages. // Get a Vec of Packages.
let actual_packages = package_map let actual_packages = package_map
.drain() .into_iter()
.filter_map(|(pkg_id, pkg)| node_map.get(&pkg_id).map(|_| pkg)) .filter_map(|(pkg_id, pkg)| node_map.get(&pkg_id).map(|_| pkg))
.collect(); .collect();
let mr = MetadataResolve { let mr = MetadataResolve {
nodes: node_map.drain().map(|(_pkg_id, node)| node).collect(), nodes: node_map.into_iter().map(|(_pkg_id, node)| node).collect(),
root: ws.current_opt().map(|pkg| pkg.package_id()), root: ws.current_opt().map(|pkg| pkg.package_id()),
}; };
Ok((actual_packages, mr)) Ok((actual_packages, mr))
} }
fn build_resolve_graph_r( fn build_resolve_graph_r(
node_map: &mut HashMap<PackageId, MetadataResolveNode>, node_map: &mut BTreeMap<PackageId, MetadataResolveNode>,
pkg_id: PackageId, pkg_id: PackageId,
resolve: &Resolve, resolve: &Resolve,
package_map: &HashMap<PackageId, Package>, package_map: &BTreeMap<PackageId, Package>,
target_data: &RustcTargetData, target_data: &RustcTargetData,
requested_kinds: &[CompileKind], requested_kinds: &[CompileKind],
) { ) {