Skip to content

Commit f9c4532

Browse files
committed
fix(dist/manifest): sort keys when serializing Manifest
1 parent dc8f2f3 commit f9c4532

4 files changed

Lines changed: 93 additions & 19 deletions

File tree

src/dist/manifest.rs

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@
1212
//!
1313
//! Docs: <https://forge.rust-lang.org/infra/channel-layout.html>
1414
15-
use std::collections::HashMap;
16-
use std::collections::hash_map::Entry;
17-
use std::fmt;
18-
use std::hash::{Hash, Hasher};
19-
use std::str::FromStr;
15+
use std::{
16+
collections::{BTreeMap, btree_map::Entry},
17+
fmt,
18+
hash::{Hash, Hasher},
19+
str::FromStr,
20+
};
2021

2122
use anyhow::{Context, Result, anyhow, bail};
2223
use serde::{Deserialize, Serialize};
@@ -41,13 +42,13 @@ pub struct Manifest {
4142
pub(crate) manifest_version: ManifestVersion,
4243
pub date: String,
4344
#[serde(default, rename = "pkg")]
44-
pub packages: HashMap<String, Package>,
45+
pub packages: BTreeMap<String, Package>,
4546
#[serde(default)]
46-
pub renames: HashMap<String, Renamed>,
47+
pub renames: BTreeMap<String, Renamed>,
4748
#[serde(default, skip_serializing)]
48-
pub reverse_renames: HashMap<String, String>,
49+
pub reverse_renames: BTreeMap<String, String>,
4950
#[serde(default)]
50-
pub profiles: HashMap<Profile, Vec<String>>,
51+
pub profiles: BTreeMap<Profile, Vec<String>>,
5152
}
5253

5354
impl Manifest {
@@ -94,12 +95,12 @@ pub struct Package {
9495
#[serde(from = "TargetsMap", into = "TargetsMap")]
9596
pub enum PackageTargets {
9697
Wildcard(TargetedPackage),
97-
Targeted(HashMap<TargetTriple, TargetedPackage>),
98+
Targeted(BTreeMap<TargetTriple, TargetedPackage>),
9899
}
99100

100101
#[derive(Deserialize, Serialize)]
101102
#[serde(transparent)]
102-
struct TargetsMap(HashMap<TargetTriple, TargetedPackage>);
103+
struct TargetsMap(BTreeMap<TargetTriple, TargetedPackage>);
103104

104105
impl From<TargetsMap> for PackageTargets {
105106
fn from(mut map: TargetsMap) -> Self {
@@ -115,7 +116,7 @@ impl From<PackageTargets> for TargetsMap {
115116
fn from(targets: PackageTargets) -> Self {
116117
match targets {
117118
PackageTargets::Wildcard(tpkg) => {
118-
let mut map = HashMap::new();
119+
let mut map = BTreeMap::new();
119120
map.insert(TargetTriple::new("*"), tpkg);
120121
Self(map)
121122
}
@@ -639,6 +640,9 @@ mod tests {
639640

640641
// Example manifest from https://public.etherpad-mozilla.org/p/Rust-infra-work-week
641642
static EXAMPLE: &str = include_str!("manifest/tests/channel-rust-nightly-example.toml");
643+
// Same manifest as above, but with the packages in a different order.
644+
static EXAMPLE_REORDERED: &str =
645+
include_str!("manifest/tests/channel-rust-nightly-example.toml");
642646
// From brson's live build-rust-manifest.py script
643647
static EXAMPLE2: &str = include_str!("manifest/tests/channel-rust-nightly-example2.toml");
644648

@@ -742,4 +746,13 @@ date = "2015-10-10"
742746

743747
assert!(Manifest::parse(&manifest).is_ok());
744748
}
749+
750+
// #4715
751+
#[test]
752+
fn manifest_serialized_with_sorted_keys() -> anyhow::Result<()> {
753+
let manifest = Manifest::parse(EXAMPLE)?;
754+
let manifest_reordered = Manifest::parse(EXAMPLE_REORDERED)?;
755+
assert_eq!(manifest.stringify()?, manifest_reordered.stringify()?);
756+
Ok(())
757+
}
745758
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
manifest-version = "2"
2+
date = "2015-10-10"
3+
[pkg.rustc]
4+
version = "rustc 1.3.0 (9a92aaf19 2015-09-15)"
5+
[pkg.cargo.target.x86_64-unknown-linux-gnu]
6+
available = true
7+
url = "example.com"
8+
hash = "..."
9+
[pkg.rustc.target.x86_64-unknown-linux-gnu]
10+
available = true
11+
url = "example.com"
12+
hash = "..."
13+
[pkg.cargo]
14+
version = "cargo 0.4.0-nightly (553b363 2015-08-03)"
15+
[pkg.rust-std]
16+
version = "rustc 1.3.0 (9a92aaf19 2015-09-15)"
17+
[pkg.rust-std.target.x86_64-unknown-linux-gnu]
18+
available = true
19+
url = "example.com"
20+
hash = "..."
21+
[pkg.rust-std.target.x86_64-unknown-linux-musl]
22+
available = true
23+
url = "example.com"
24+
hash = "..."
25+
[pkg.rust-std.target.i686-unknown-linux-gnu]
26+
available = true
27+
url = "example.com"
28+
hash = "..."
29+
[pkg.rust-docs]
30+
version = "rustc 1.3.0 (9a92aaf19 2015-09-15)"
31+
[pkg.rust-docs.target.x86_64-unknown-linux-gnu]
32+
available = true
33+
hash = "..."
34+
url = "example.com"
35+
[pkg.rust]
36+
version = "rustc 1.3.0 (9a92aaf19 2015-09-15)"
37+
[pkg.rust.target.x86_64-unknown-linux-gnu]
38+
available = true
39+
url = "example.com"
40+
hash = "..."
41+
[[pkg.rust.target.x86_64-unknown-linux-gnu.components]]
42+
pkg = "rustc"
43+
target = "x86_64-unknown-linux-gnu"
44+
[[pkg.rust.target.x86_64-unknown-linux-gnu.components]]
45+
pkg = "rust-docs"
46+
target = "x86_64-unknown-linux-gnu"
47+
[[pkg.rust.target.x86_64-unknown-linux-gnu.components]]
48+
pkg = "cargo"
49+
target = "x86_64-unknown-linux-gnu"
50+
[[pkg.rust.target.x86_64-unknown-linux-gnu.components]]
51+
pkg = "rust-std"
52+
target = "x86_64-unknown-linux-gnu"
53+
# extensions are rust-std or rust-docs that aren't in the rust tarball's component list
54+
[[pkg.rust.target.x86_64-unknown-linux-gnu.extensions]]
55+
pkg = "rust-std"
56+
target = "x86_64-unknown-linux-musl"
57+
[[pkg.rust.target.x86_64-unknown-linux-gnu.extensions]]
58+
pkg = "rust-std"
59+
target = "i686-unknown-linux-gnu"

src/dist/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -725,7 +725,9 @@ impl TryFrom<&ToolchainName> for ToolchainDesc {
725725
}
726726
}
727727

728-
#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize)]
728+
#[derive(
729+
Clone, Copy, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize, PartialOrd, Ord,
730+
)]
729731
#[serde(rename_all = "kebab-case")]
730732
pub enum Profile {
731733
Minimal,

src/test/dist.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Tools for building and working with the filesystem of a mock Rust
22
//! distribution server, with v1 and v2 manifests.
33
4-
use std::collections::HashMap;
4+
use std::collections::{BTreeMap, HashMap};
55
use std::fs::{self, File};
66
use std::io::{self, Read, Write};
77
use std::path::{Path, PathBuf};
@@ -771,15 +771,15 @@ impl MockDistServer {
771771
let mut manifest = Manifest {
772772
manifest_version: ManifestVersion::V2,
773773
date: channel.date.clone(),
774-
renames: HashMap::default(),
775-
packages: HashMap::default(),
776-
reverse_renames: HashMap::default(),
777-
profiles: HashMap::default(),
774+
renames: BTreeMap::default(),
775+
packages: BTreeMap::default(),
776+
reverse_renames: BTreeMap::default(),
777+
profiles: BTreeMap::default(),
778778
};
779779

780780
// [pkg.*]
781781
for package in &channel.packages {
782-
let mut targets = HashMap::default();
782+
let mut targets = BTreeMap::default();
783783

784784
// [pkg.*.target.*]
785785
for target in &package.targets {

0 commit comments

Comments
 (0)