diff options
Diffstat (limited to 'test_util/src/servers/registry.rs')
-rw-r--r-- | test_util/src/servers/registry.rs | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/test_util/src/servers/registry.rs b/test_util/src/servers/registry.rs index 69728f706..0efe06217 100644 --- a/test_util/src/servers/registry.rs +++ b/test_util/src/servers/registry.rs @@ -13,9 +13,14 @@ use hyper::body::Incoming; use hyper::Request; use hyper::Response; use hyper::StatusCode; +use once_cell::sync::Lazy; use serde_json::json; +use std::collections::BTreeMap; +use std::collections::HashMap; use std::convert::Infallible; use std::net::SocketAddr; +use std::path::Path; +use std::sync::Mutex; pub async fn registry_server(port: u16) { let registry_server_addr = SocketAddr::from(([127, 0, 0, 1], port)); @@ -66,6 +71,27 @@ async fn registry_server_handler( testdata_path().to_path_buf().join("jsr").join("registry"); file_path.push(&req.uri().path()[1..].replace("%2f", "/")); if let Ok(body) = tokio::fs::read(&file_path).await { + let body = if let Some(version) = file_path + .file_name() + .unwrap() + .to_string_lossy() + .strip_suffix("_meta.json") + { + // fill the manifest with checksums found in the directory so that + // we don't need to maintain them manually in the testdata directory + let mut meta: serde_json::Value = serde_json::from_slice(&body)?; + let mut manifest = + manifest_sorted(meta.get("manifest").cloned().unwrap_or(json!({}))); + let version_dir = file_path.parent().unwrap().join(version); + fill_manifest_at_dir(&mut manifest, &version_dir); + meta + .as_object_mut() + .unwrap() + .insert("manifest".to_string(), json!(manifest)); + serde_json::to_string(&meta).unwrap().into_bytes() + } else { + body + }; return Ok(Response::new(UnsyncBoxBody::new( http_body_util::Full::new(Bytes::from(body)), ))); @@ -77,3 +103,80 @@ async fn registry_server_handler( .body(empty_body)?; Ok(res) } + +fn manifest_sorted( + meta: serde_json::Value, +) -> BTreeMap<String, serde_json::Value> { + let mut manifest = BTreeMap::new(); + if let serde_json::Value::Object(files) = meta { + for (file, checksum) in files { + manifest.insert(file.clone(), checksum.clone()); + } + } + manifest +} + +fn fill_manifest_at_dir( + manifest: &mut BTreeMap<String, serde_json::Value>, + dir: &Path, +) { + let file_system_manifest = get_manifest_entries_for_dir(dir); + for (file_path, value) in file_system_manifest { + manifest.entry(file_path).or_insert(value); + } +} + +static DIR_MANIFEST_CACHE: Lazy< + Mutex<HashMap<String, BTreeMap<String, serde_json::Value>>>, +> = Lazy::new(Default::default); + +fn get_manifest_entries_for_dir( + dir: &Path, +) -> BTreeMap<String, serde_json::Value> { + fn inner_fill( + root_dir: &Path, + dir: &Path, + manifest: &mut BTreeMap<String, serde_json::Value>, + ) { + for entry in std::fs::read_dir(dir).unwrap() { + let entry = entry.unwrap(); + let path = entry.path(); + if path.is_file() { + let file_bytes = std::fs::read(&path).unwrap(); + let checksum = format!("sha256-{}", get_checksum(&file_bytes)); + let relative_path = path + .to_string_lossy() + .strip_prefix(&root_dir.to_string_lossy().to_string()) + .unwrap() + .replace('\\', "/"); + manifest.insert( + relative_path, + json!({ + "size": file_bytes.len(), + "checksum": checksum, + }), + ); + } else if path.is_dir() { + inner_fill(root_dir, &path, manifest); + } + } + } + + DIR_MANIFEST_CACHE + .lock() + .unwrap() + .entry(dir.to_string_lossy().to_string()) + .or_insert_with(|| { + let mut manifest = BTreeMap::new(); + inner_fill(dir, dir, &mut manifest); + manifest + }) + .clone() +} + +fn get_checksum(bytes: &[u8]) -> String { + use sha2::Digest; + let mut hasher = sha2::Sha256::new(); + hasher.update(bytes); + format!("{:x}", hasher.finalize()) +} |