Skip to content

Commit fc491c2

Browse files
committed
Add support for new index hash implementation.
1 parent 0b0ceb8 commit fc491c2

File tree

2 files changed

+74
-10
lines changed

2 files changed

+74
-10
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ http = { version = "1", optional = true }
4545
memchr = "2.5.0"
4646
rayon = { version = "1.7.0", optional = true }
4747
rustc-hash = "2.0.0"
48+
rustc-stable-hash = "0.1.1"
4849
semver = "1.0.17"
4950
serde = { version = "1.0.160", features = ["rc"] }
5051
serde_derive = "1.0.160"

src/dirs.rs

Lines changed: 73 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,23 @@ pub fn local_path_and_canonical_url(
99
url: &str,
1010
cargo_home: Option<&std::path::Path>,
1111
) -> Result<(std::path::PathBuf, String), Error> {
12-
let (dir_name, canonical_url) = url_to_local_dir(url)?;
13-
1412
let mut path = match cargo_home {
1513
Some(path) => path.to_owned(),
1614
None => home::cargo_home()?,
1715
};
1816

1917
path.push("registry");
2018
path.push("index");
21-
path.push(dir_name);
19+
20+
let (dir_name, canonical) = url_to_local_dir(url, true)?;
21+
let canonical_url = if path.join(&dir_name).exists() {
22+
path.push(dir_name);
23+
canonical
24+
} else {
25+
let (dir_name, canonical) = url_to_local_dir(url, false)?;
26+
path.push(dir_name);
27+
canonical
28+
};
2229

2330
Ok((path, canonical_url))
2431
}
@@ -72,8 +79,8 @@ pub(crate) fn crate_name_to_relative_path(crate_name: &str, separator: Option<ch
7279

7380
/// Converts a full url, eg https://github.com/rust-lang/crates.io-index, into
7481
/// the root directory name where cargo itself will fetch it on disk
75-
fn url_to_local_dir(url: &str) -> Result<(String, String), Error> {
76-
fn to_hex(num: u64) -> String {
82+
fn url_to_local_dir(url: &str, use_stable_hash: bool) -> Result<(String, String), Error> {
83+
fn legacy_to_hex(num: u64) -> String {
7784
const CHARS: &[u8] = b"0123456789abcdef";
7885

7986
let bytes = &[
@@ -102,7 +109,7 @@ fn url_to_local_dir(url: &str) -> Result<(String, String), Error> {
102109
}
103110

104111
#[allow(deprecated)]
105-
fn hash_u64(url: &str, registry_kind: u64) -> u64 {
112+
fn legacy_hash_u64(url: &str, registry_kind: u64) -> u64 {
106113
use std::hash::{Hash, Hasher, SipHasher};
107114

108115
let mut hasher = SipHasher::new_with_keys(0, 0);
@@ -113,6 +120,35 @@ fn url_to_local_dir(url: &str) -> Result<(String, String), Error> {
113120
hasher.finish()
114121
}
115122

123+
fn stable_to_hex(num: u64) -> String {
124+
hex::encode(num.to_le_bytes())
125+
}
126+
127+
fn stable_hash_u64(url: &str, registry_kind: u64) -> u64 {
128+
// Matches https://github.com/rust-lang/cargo/blob/49e5d24870a13cd3f26ad61159045788b36efcdf/src/cargo/util/hasher.rs#L6
129+
use rustc_stable_hash::StableSipHasher128 as StableHasher;
130+
use std::hash::{Hash, Hasher};
131+
132+
let mut hasher = StableHasher::new();
133+
// Registry
134+
registry_kind.hash(&mut hasher);
135+
// Url
136+
url.hash(&mut hasher);
137+
Hasher::finish(&hasher)
138+
}
139+
140+
let hash_u64 = if use_stable_hash {
141+
stable_hash_u64
142+
} else {
143+
legacy_hash_u64
144+
};
145+
146+
let to_hex = if use_stable_hash {
147+
stable_to_hex
148+
} else {
149+
legacy_to_hex
150+
};
151+
116152
// SourceKind::Registry
117153
let mut registry_kind = 2;
118154

@@ -190,35 +226,62 @@ mod test {
190226
fn http_index_url_matches_cargo() {
191227
use crate::sparse::URL;
192228
assert_eq!(
193-
super::url_to_local_dir(URL).unwrap(),
229+
super::url_to_local_dir(URL, false).unwrap(),
194230
("index.crates.io-6f17d22bba15001f".to_owned(), URL.to_owned(),)
195231
);
232+
assert_eq!(
233+
super::url_to_local_dir(URL, true).unwrap(),
234+
("index.crates.io-1949cf8c6b5b557f".to_owned(), URL.to_owned(),)
235+
);
196236

197237
// I've confirmed this also works with a custom registry, unfortunately
198238
// that one includes a secret key as part of the url which would allow
199239
// anyone to publish to the registry, so uhh...here's a fake one instead
200240
assert_eq!(
201-
super::url_to_local_dir("https://dl.cloudsmith.io/aBcW1234aBcW1234/embark/rust/cargo/index.git").unwrap(),
241+
super::url_to_local_dir(
242+
"https://dl.cloudsmith.io/aBcW1234aBcW1234/embark/rust/cargo/index.git",
243+
false
244+
)
245+
.unwrap(),
202246
(
203247
"dl.cloudsmith.io-ff79e51ddd2b38fd".to_owned(),
204248
"https://dl.cloudsmith.io/aBcW1234aBcW1234/embark/rust/cargo/index.git".to_owned()
205249
)
206250
);
251+
assert_eq!(
252+
super::url_to_local_dir(
253+
"https://dl.cloudsmith.io/aBcW1234aBcW1234/embark/rust/cargo/index.git",
254+
true
255+
)
256+
.unwrap(),
257+
(
258+
"dl.cloudsmith.io-fade991491aaf150".to_owned(),
259+
"https://dl.cloudsmith.io/aBcW1234aBcW1234/embark/rust/cargo/index.git".to_owned()
260+
)
261+
);
207262
}
208263

209264
#[test]
210265
#[cfg(feature = "git")]
211266
fn git_url_matches_cargo() {
212267
use crate::git::URL;
213268
assert_eq!(
214-
crate::dirs::url_to_local_dir(URL).unwrap(),
269+
crate::dirs::url_to_local_dir(URL, false).unwrap(),
270+
("github.com-1ecc6299db9ec823".to_owned(), URL.to_owned())
271+
);
272+
assert_eq!(
273+
crate::dirs::url_to_local_dir(URL, true).unwrap(),
215274
("github.com-1ecc6299db9ec823".to_owned(), URL.to_owned())
216275
);
217276

218277
// Ensure we actually strip off the irrelevant parts of a url, note that
219278
// the .git suffix is not part of the canonical url, but *is* used when hashing
220279
assert_eq!(
221-
crate::dirs::url_to_local_dir(&format!("registry+{}.git?one=1&two=2#fragment", URL)).unwrap(),
280+
crate::dirs::url_to_local_dir(&format!("registry+{}.git?one=1&two=2#fragment", URL), false).unwrap(),
281+
("github.com-c786010fb7ef2e6e".to_owned(), URL.to_owned())
282+
);
283+
assert_eq!(
284+
crate::dirs::url_to_local_dir(&format!("registry+{}.git?one=1&two=2#fragment", URL), true).unwrap(),
222285
("github.com-c786010fb7ef2e6e".to_owned(), URL.to_owned())
223286
);
224287
}

0 commit comments

Comments
 (0)