holperf/src/seed2.rs
//! The second half of the plain-backend formats: Docker/OCI (both crates), Helm,
//! deb, rpm, the znippy package, the Build Thing and raw.
use std::path::Path;
use std::sync::Arc;
use anyhow::Result;
use traits::{ArtifactId, RepositoryBackendTrait};
use crate::gen;
use crate::harness::Scenario;
use crate::seed::{pack, want, Open};
fn name(i: usize) -> String {
format!("pkg{i:05}")
}
fn picks(n: usize) -> Vec<usize> {
(0..64).map(|k| (k * 7919) % n).collect()
}
pub fn more(
root: &Path,
n: usize,
small: usize,
large: usize,
only: Option<&[String]>,
v: &mut Vec<Scenario>,
) -> Result<()> {
let sc = |format: &'static str,
route: &str,
open: Open,
dir: std::path::PathBuf,
index: Vec<String>,
meta2: Vec<String>,
sm: Vec<String>,
lg: Vec<String>| Scenario {
format,
route: route.into(),
open,
dir,
index,
meta2,
small: sm,
large: lg,
small_size: small as u64,
large_size: large as u64,
packages: n,
};
// ── Docker, the read-only znippy registry (format "docker") ──
if want(only, "docker") {
let dir = root.join(format!("docker-{n}"));
let big = gen::payload(7, large);
let bigd = format!("sha256:{}", gen::sha256_hex(&big));
let a = pack(
&dir,
|| {
let mut f = Vec::new();
for i in 0..n {
let blob = gen::payload(i as u64, small);
let d = format!("sha256:{}", gen::sha256_hex(&blob));
let cfg = format!("sha256:{}", gen::sha256_hex(b"{}"));
let m = gen::oci_manifest(&cfg, &d, small);
f.push((
format!("v2/docker/{}/manifests/1.0", name(i)),
m.clone().into_bytes(),
));
f.push((
format!("v2/docker/{}/manifests/1.1", name(i)),
m.into_bytes(),
));
f.push((format!("v2/docker/{}/blobs/{d}", name(i)), blob));
}
f.push((format!("v2/docker/bigpkg/blobs/{bigd}"), big.clone()));
f
},
None,
)?;
let sm = picks(n)
.iter()
.map(|&i| {
format!(
"/v2/docker/{}/blobs/sha256:{}",
name(i),
gen::sha256_hex(&gen::payload(i as u64, small))
)
})
.collect();
let open: Open = Box::new(move || {
Arc::new(r_docker::DockerRepoZnippy::with_archive("docker".into(), a.clone()).unwrap())
});
v.push(sc(
"docker",
"docker",
open,
dir,
picks(n)
.iter()
.map(|&i| format!("/v2/docker/{}/tags/list", name(i)))
.collect(),
picks(n)
.iter()
.map(|&i| format!("/v2/docker/{}/manifests/1.0", name(i)))
.collect(),
sm,
vec![format!("/v2/docker/bigpkg/blobs/{bigd}")],
));
}
// ── OCI, the writable file registry (format "oci", the estate's registry) ──
if want(only, "oci") {
let dir = root.join(format!("oci-{n}"));
let big = gen::payload(7, large);
let bigd = format!("sha256:{}", gen::sha256_hex(&big));
if !dir.join("seeded").exists() {
let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(&dir)?;
let r = r_oci::OciRepoFile::new("oci".into(), dir.join("store"))?;
let cfg = format!("sha256:{}", gen::sha256_hex(b"{}"));
r.handle_http2_request(
"POST",
&format!("/v2/oci/x/blobs/uploads/?digest={cfg}"),
b"{}",
)?;
for i in 0..n {
let blob = gen::payload(i as u64, small);
let d = format!("sha256:{}", gen::sha256_hex(&blob));
let st = r
.handle_http2_request(
"POST",
&format!("/v2/oci/{}/blobs/uploads/?digest={d}", name(i)),
&blob,
)?
.0;
anyhow::ensure!(st == 201, "oci blob upload {st}");
let m = gen::oci_manifest(&cfg, &d, small);
for t in ["1.0", "1.1"] {
let st = r
.handle_http2_request(
"PUT",
&format!("/v2/oci/{}/manifests/{t}", name(i)),
m.as_bytes(),
)?
.0;
anyhow::ensure!(st == 201, "oci manifest put {st}");
}
}
r.handle_http2_request(
"POST",
&format!("/v2/oci/bigpkg/blobs/uploads/?digest={bigd}"),
&big,
)?;
std::fs::write(dir.join("seeded"), b"")?;
}
let store = dir.join("store");
let sm = picks(n)
.iter()
.map(|&i| {
format!(
"/v2/oci/{}/blobs/sha256:{}",
name(i),
gen::sha256_hex(&gen::payload(i as u64, small))
)
})
.collect();
let open: Open = Box::new(move || {
Arc::new(r_oci::OciRepoFile::new("oci".into(), store.clone()).unwrap())
});
v.push(sc(
"oci",
"oci",
open,
dir,
picks(n)
.iter()
.map(|&i| format!("/v2/oci/{}/tags/list", name(i)))
.collect(),
picks(n)
.iter()
.map(|&i| format!("/v2/oci/{}/manifests/1.0", name(i)))
.collect(),
sm,
vec![format!("/v2/oci/bigpkg/blobs/{bigd}")],
));
}
// ── Helm (index.yaml synthesized once from every chart's Chart.yaml) ──
if want(only, "helm") {
let dir = root.join(format!("helm-{n}"));
let a = pack(
&dir,
|| {
let mut f = Vec::new();
for i in 0..n {
for (j, ver) in ["1.0.0", "1.1.0"].iter().enumerate() {
f.push((
format!("{}-{ver}.tgz", name(i)),
gen::chart(&name(i), ver, small, (i * 2 + j) as u64),
));
}
}
f.push((
"bigpkg-1.0.0.tgz".into(),
gen::chart("bigpkg", "1.0.0", large, 7),
));
f
},
None,
)?;
let open: Open = Box::new(move || {
Arc::new(r_helm::HelmRepoZnippy::with_archive("helm".into(), a.clone()).unwrap())
});
v.push(sc(
"helm",
"helm",
open,
dir,
vec!["/helm/index.yaml".into()],
vec![],
picks(n)
.iter()
.map(|&i| format!("/helm/{}-1.0.0.tgz", name(i)))
.collect(),
vec!["/helm/bigpkg-1.0.0.tgz".into()],
));
}
// ── deb (Packages + Release synthesized once, control parsed via ar + xz) ──
if want(only, "deb") {
let dir = root.join(format!("deb-{n}"));
let a = pack(
&dir,
|| {
let mut f = Vec::new();
for i in 0..n {
for (j, ver) in ["1.0.0", "1.1.0"].iter().enumerate() {
f.push((
format!("pool/main/p/{0}/{0}_{ver}_amd64.deb", name(i)),
gen::deb(&name(i), ver, "amd64", small, (i * 2 + j) as u64),
));
}
}
f.push((
"pool/main/b/bigpkg/bigpkg_1.0.0_amd64.deb".into(),
gen::deb("bigpkg", "1.0.0", "amd64", large, 7),
));
f
},
None,
)?;
let open: Open = Box::new(move || {
Arc::new(r_deb::DebRepoZnippy::with_archive("deb".into(), a.clone()).unwrap())
});
v.push(sc(
"deb",
"deb",
open,
dir,
vec!["/deb/dists/stable/main/binary-amd64/Packages".into()],
vec!["/deb/dists/stable/Release".into()],
picks(n)
.iter()
.map(|&i| format!("/deb/pool/main/p/{0}/{0}_1.0.0_amd64.deb", name(i)))
.collect(),
vec!["/deb/pool/main/b/bigpkg/bigpkg_1.0.0_amd64.deb".into()],
));
}
// ── rpm (repomd.xml + primary.xml synthesized once, header parsed) ──
if want(only, "rpm") {
let dir = root.join(format!("rpm-{n}"));
let a = pack(
&dir,
|| {
let mut f = Vec::new();
for i in 0..n {
for (j, ver) in ["1.0.0", "1.1.0"].iter().enumerate() {
let nvr = format!("{}-{ver}-1", name(i));
f.push((
format!("Packages/{nvr}.x86_64.rpm"),
gen::rpm(&nvr, small, (i * 2 + j) as u64),
));
}
}
f.push((
"Packages/bigpkg-1.0.0-1.x86_64.rpm".into(),
gen::rpm("bigpkg-1.0.0-1", large, 7),
));
f
},
None,
)?;
let open: Open = Box::new(move || {
Arc::new(r_rpm::RpmRepoZnippy::with_archive("rpm".into(), a.clone()).unwrap())
});
v.push(sc(
"rpm",
"rpm",
open,
dir,
vec!["/rpm/repodata/primary.xml".into()],
vec!["/rpm/repodata/repomd.xml".into()],
picks(n)
.iter()
.map(|&i| format!("/rpm/Packages/{}-1.0.0-1.x86_64.rpm", name(i)))
.collect(),
vec!["/rpm/Packages/bigpkg-1.0.0-1.x86_64.rpm".into()],
));
}
// ── znippy package ──
if want(only, "znippy") {
let dir = root.join(format!("znippy-{n}"));
let a = pack(
&dir,
|| {
let mut f = Vec::new();
for i in 0..n {
for (j, ver) in ["1.0.0", "1.1.0"].iter().enumerate() {
f.push((
format!("{}-{ver}.znippy", name(i)),
gen::payload((i * 2 + j) as u64, small),
));
}
}
f.push(("bigpkg-1.0.0.znippy".into(), gen::payload(7, large)));
f
},
None,
)?;
let open: Open = Box::new(move || {
Arc::new(r_package::ZnippyRepoZnippy::with_archive("pkgs".into(), a.clone()).unwrap())
});
v.push(sc(
"znippy",
"pkgs",
open,
dir,
vec!["/pkgs/".into()],
vec![],
picks(n)
.iter()
.map(|&i| format!("/pkgs/{}/1.0.0", name(i)))
.collect(),
vec!["/pkgs/bigpkg/1.0.0".into()],
));
}
// ── Build Thing (index.json + attestations, pure path maps) ──
if want(only, "buildthing") {
let dir = root.join(format!("bt-{n}"));
let shas: Vec<String> = (0..n)
.map(|i| gen::sha256_hex(&gen::payload(i as u64, 64)))
.collect();
let s2 = shas.clone();
let a = pack(
&dir,
move || {
let mut f = Vec::new();
let atts: Vec<_> = s2
.iter()
.map(|h| serde_json::json!({ "artifact_sha256": h }))
.collect();
f.push((
"index.json".into(),
serde_json::to_vec(
&serde_json::json!({ "kind": "znippy-build-thing", "attestations": atts }),
)
.unwrap(),
));
for (i, h) in s2.iter().enumerate() {
f.push((format!("attestations/{h}.json"), serde_json::to_vec(&serde_json::json!({ "artifact_sha256": h, "recipe": name(i), "blob": gen::sha256_hex(&gen::payload(i as u64, small)) })).unwrap()));
f.push((
format!("by-atom/{}", name(i)),
gen::payload(i as u64, small),
));
}
f.push(("by-atom/bigpkg".into(), gen::payload(7, large)));
f
},
None,
)?;
let open: Open = Box::new(move || {
Arc::new(r_bt::BuildThingRepoZnippy::with_archive("bt".into(), a.clone()).unwrap())
});
v.push(sc(
"buildthing",
"bt",
open,
dir,
vec!["/bt/".into()],
picks(n)
.iter()
.map(|&i| format!("/bt/artifact/{}", shas[i]))
.collect(),
picks(n)
.iter()
.map(|&i| format!("/bt/atom/{}", name(i)))
.collect(),
vec!["/bt/atom/bigpkg".into()],
));
}
// ── raw (loose files, the streamed door) ──
if want(only, "raw") {
let dir = root.join(format!("raw-{n}"));
let base = dir.join("store");
if !dir.join("seeded").exists() {
let _ = std::fs::remove_dir_all(&dir);
let r = server_lib::raw::RawBackend::new("raw".into(), base.clone());
for i in 0..n {
for (j, ver) in ["1.0.0", "1.1.0"].iter().enumerate() {
let id = ArtifactId {
namespace: None,
name: format!("{}/{ver}/blob.bin", name(i)),
version: String::new(),
};
r.put(&id, &gen::payload((i * 2 + j) as u64, small))?;
}
}
let id = ArtifactId {
namespace: None,
name: "bigpkg/1.0.0/blob.bin".into(),
version: String::new(),
};
r.put(&id, &gen::payload(7, large))?;
std::fs::write(dir.join("seeded"), b"")?;
}
let open: Open = Box::new(move || {
Arc::new(server_lib::raw::RawBackend::new("raw".into(), base.clone()))
});
v.push(sc(
"raw",
"raw",
open,
dir,
vec![],
vec![],
picks(n)
.iter()
.map(|&i| format!("/raw/{}/1.0.0/blob.bin", name(i)))
.collect(),
vec!["/raw/bigpkg/1.0.0/blob.bin".into()],
));
}
// ── Composer and NuGet (the package lists read every package's manifest out of
// its zip, lane HOL-RSS-3): `big` large packages beside the small ones, so the
// first index request (the list's build) meets them all ──
let big = std::env::var("HOLPERF_ZIP_BIG")
.ok()
.and_then(|s| s.parse().ok())
.unwrap_or(16usize);
if want(only, "composer") {
let dir = root.join(format!("composer-{n}-{big}"));
let dist = |pkg: &str, size: usize, seed: u64| {
let manifest = format!(
r#"{{"name":"holperf/{pkg}","description":"holperf","type":"library","license":["MIT"]}}"#
);
gen::zip(&[
("composer.json", manifest.as_bytes()),
("src/blob.bin", &gen::payload(seed, size)),
])
};
let a = pack(
&dir,
|| {
let mut f = Vec::new();
for i in 0..n {
f.push((
format!("dist/holperf/{}/1.0.0.zip", name(i)),
dist(&name(i), small, i as u64),
));
}
for k in 0..big {
f.push((
format!("dist/holperf/bigpkg{k}/1.0.0.zip"),
dist(&format!("bigpkg{k}"), large, 7 + k as u64),
));
}
f
},
None,
)?;
let open: Open = Box::new(move || {
Arc::new(
r_composer::ComposerRepoZnippy::with_archive("composer".into(), a.clone()).unwrap(),
)
});
v.push(sc(
"composer",
"composer",
open,
dir,
picks(n)
.iter()
.map(|&i| format!("/composer/p2/holperf/{}.json", name(i)))
.collect(),
vec!["/composer/packages.json".into()],
picks(n)
.iter()
.map(|&i| format!("/composer/dist/holperf/{}/1.0.0.zip", name(i)))
.collect(),
vec!["/composer/dist/holperf/bigpkg0/1.0.0.zip".into()],
));
}
if want(only, "nuget") {
let dir = root.join(format!("nuget-{n}-{big}"));
let nupkg = |id: &str, size: usize, seed: u64| {
let nuspec = format!(
"<?xml version=\"1.0\"?>\n<package><metadata><id>{id}</id><version>1.0.0</version>\
<authors>holperf</authors><description>holperf</description></metadata></package>"
);
gen::zip(&[
(format!("{id}.nuspec").as_str(), nuspec.as_bytes()),
("lib/net8.0/blob.dll", &gen::payload(seed, size)),
])
};
let a = pack(
&dir,
|| {
let mut f = Vec::new();
for i in 0..n {
f.push((
format!("{0}/1.0.0/{0}.1.0.0.nupkg", name(i)),
nupkg(&name(i), small, i as u64),
));
}
for k in 0..big {
f.push((
format!("bigpkg{k}/1.0.0/bigpkg{k}.1.0.0.nupkg"),
nupkg(&format!("bigpkg{k}"), large, 7 + k as u64),
));
}
f
},
None,
)?;
let open: Open = Box::new(move || {
Arc::new(r_nuget::NugetRepoZnippy::with_archive("nuget".into(), a.clone()).unwrap())
});
v.push(sc(
"nuget",
"nuget",
open,
dir,
picks(n)
.iter()
.map(|&i| format!("/nuget/v3/registration/{}/index.json", name(i)))
.collect(),
vec!["/nuget/v3/index.json".into()],
picks(n)
.iter()
.map(|&i| format!("/nuget/v3-flatcontainer/{0}/1.0.0/{0}.1.0.0.nupkg", name(i)))
.collect(),
vec!["/nuget/v3-flatcontainer/bigpkg0/1.0.0/bigpkg0.1.0.0.nupkg".into()],
));
}
Ok(())
}