#![cfg(all(feature = "local-builder", feature = "sparse"))] mod utils; use rayon::prelude::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator}; use tame_index::index::local; #[test] fn builds_local_registry() { let sparse = tame_index::index::RemoteSparseIndex::new( tame_index::SparseIndex::new(tame_index::IndexLocation::new( tame_index::IndexUrl::CratesIoSparse, )) .unwrap(), reqwest::blocking::Client::new(), ); let mut mdc = cargo_metadata::MetadataCommand::new(); mdc.features(cargo_metadata::CargoOpt::AllFeatures); mdc.manifest_path("Cargo.toml"); let md = mdc.exec().expect("failed to gather metadata"); let mut krates = std::collections::BTreeMap::new(); struct IndexPkg { ik: tame_index::IndexKrate, versions: Vec, } let lock = tame_index::utils::flock::FileLock::unlocked(); for pkg in &md.packages { if pkg.name == "tame-index" { continue; } let ip = krates.entry(pkg.name.clone()).or_insert_with(|| { let ik = sparse .cached_krate(pkg.name.as_str().try_into().unwrap(), &lock) .map_err(|e| { panic!("failed to read cache entry for {}: {e}", pkg.name); }) .unwrap() .ok_or_else(|| { panic!("no cache entry for {}", pkg.name); }) .unwrap(); IndexPkg { ik, versions: Vec::new(), } }); ip.versions.push(pkg.version.to_string().into()); } let client = local::builder::Client::build(reqwest::blocking::ClientBuilder::new()).unwrap(); let lrb_td = utils::tempdir(); let lrb = local::LocalRegistryBuilder::create(lrb_td.path().to_owned()).unwrap(); let config = sparse.index.index_config().unwrap(); krates.into_par_iter().for_each(|(_krate, ipkg)| { let mut crate_files = Vec::with_capacity(ipkg.versions.len()); ipkg.versions .into_par_iter() .map(|vers| { let iv = ipkg .ik .versions .iter() .find(|iv| iv.version == vers) .unwrap(); local::ValidKrate::download(&client, &config, iv).unwrap() }) .collect_into_vec(&mut crate_files); lrb.insert(&ipkg.ik, &crate_files).unwrap(); }); let _lr = lrb.finalize(true).unwrap(); // Create a fake project and override the crates.io registry to point to // the local one we just created, it should get the same metadata let fake_project = utils::tempdir(); std::fs::copy("Cargo.toml", fake_project.path().join("Cargo.toml")).unwrap(); std::fs::copy("Cargo.lock", fake_project.path().join("Cargo.lock")).unwrap(); let mut config = fake_project.path().join(".cargo"); std::fs::create_dir(&config).unwrap(); config.push("config.toml"); // Windows is terrible let local_path = lrb_td.path().as_str(); let local_path = local_path.replace('\\', "/"); std::fs::write( &config, format!( r#" [source.crates-io] replace-with = "test-registry" [source.test-registry] local-registry = "{local_path}""#, ), ) .unwrap(); // We also need to create a fake lib.rs otherwise cargo will be sad { let librs = fake_project.path().join("src/lib.rs"); std::fs::create_dir_all(librs.parent().unwrap()).unwrap(); std::fs::write(librs, "").unwrap(); } let mut mdc = cargo_metadata::MetadataCommand::new(); mdc.features(cargo_metadata::CargoOpt::AllFeatures); mdc.manifest_path("Cargo.toml"); // We need to override this otherwise our config won't be picked up mdc.current_dir(fake_project.path()); // This will fail if we've missed one or more versions in the local registry mdc.exec().expect("failed to gather metadata"); } /// Validates we get the correct checksum for a crate #[test] fn downloads_and_verifies() { let client = reqwest::blocking::Client::builder() .no_gzip() .build() .unwrap(); let res = client .get("https://static.crates.io/crates/wasm-bindgen/wasm-bindgen-0.2.87.crate") .send() .unwrap() .error_for_status() .unwrap(); let body = res.bytes().unwrap(); use bytes::Buf; assert!(local::validate_checksum::<{ 16 * 1024 }>( body.reader(), &("7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" .parse() .unwrap()), ) .unwrap()); }