Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/holger

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(())
}