Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions crates/socket-patch-bench/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ Each scenario is one project and one `scan` invocation:

Package managers (`<pm>`), each in its native lockfile format and install
layout: `npm`, `pnpm` (isolated `.pnpm` store with symlinks), `yarn-classic`,
`yarn-berry` (node-modules linker), `bun` (text `bun.lock`), `vlt`
(`.vlt` store), `pip` (hash-pinned `requirements.txt`), `uv`, `pylock`
`yarn-berry` (node-modules linker), `bun` (text `bun.lock`, hoisted),
`bun-isolated` (the same lockfile, Bun 1.3's isolated `.bun` store),
`vlt` (`.vlt` store), `pip` (hash-pinned `requirements.txt`), `uv`, `pylock`
(PEP 751), `poetry`, `pipenv`, `pdm`, `bundler`, `composer`, `cargo`,
`golang`, `nuget` and `maven`. Deno has no hosted rewrite and is not
benchmarked separately.
Expand Down
13 changes: 11 additions & 2 deletions crates/socket-patch-bench/src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,8 +197,17 @@ impl<'a> Prepared<'a> {
let prep = crate::process::run(self.command(bin, false), &self.capture)
.map_err(|e| format!("spawning {}: {e}", bin.display()))?;
let stats = self.mock.take_stats();
validate(self, &prep, &stats, Kind::Hosted)
.map_err(|e| format!("the rescan's preparatory scan failed validation: {e}"))?;
if let Err(e) = validate(self, &prep, &stats, Kind::Hosted) {
// A failed preparatory scan can still have rewritten the
// project. Restore it, or the next run (the other binary's,
// in `compare`) starts from a rescanned tree and fails
// validation for this binary's fault.
tree::restore(&self.work, &self.pristine, &mut self.snapshot)
.map_err(|e| format!("restoring the fixture: {e}"))?;
return Err(format!(
"the rescan's preparatory scan failed validation: {e}"
));
}
}
self.mock.take_stats();
let dry = self.scenario.kind == Kind::DryRun;
Expand Down
7 changes: 7 additions & 0 deletions crates/socket-patch-bench/src/fixtures/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,13 @@ pub static ALL: &[Pm] = &[
patched: 60,
build: npm::build_bun,
},
Pm {
name: "bun-isolated",
description: "bun (text bun.lock v1, isolated node_modules/.bun store)",
packages: 3000,
patched: 60,
build: npm::build_bun_isolated,
},
Pm {
name: "vlt",
description: "vlt (vlt-lock.json v1, node_modules/.vlt store)",
Expand Down
43 changes: 42 additions & 1 deletion crates/socket-patch-bench/src/fixtures/npm.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//! npm-family projects. One deterministic dependency graph is written out
//! as each package manager's lockfile and install layout, so the six
//! as each package manager's lockfile and install layout, so the seven
//! scenarios differ only in what each package manager puts on disk.

use std::collections::BTreeMap;
Expand Down Expand Up @@ -689,6 +689,47 @@ pub fn build_bun(t: &mut Tree, size: Size) -> std::io::Result<Fixture> {
Ok(fixture(&g, g.patches(false), &["bun.lock"], &[]))
}

/// Bun's isolated linker (the default since Bun 1.3.2): the same text
/// `bun.lock`, but every package lives only in the pnpm-shaped store
/// `node_modules/.bun/<name>@<version>/node_modules/<name>` (scoped
/// `@scope+leaf@…`), its dependencies linked beside it, the root linking
/// direct dependencies only, and `.bun/node_modules` holding Bun's hoist
/// links.
pub fn build_bun_isolated(t: &mut Tree, size: Size) -> std::io::Result<Fixture> {
let g = graph("bun-isolated", size);
t.write("project/package.json", g.package_json())?;
t.write("project/bun.lock", bun_lock(&g))?;
let mut rng = Rng::new("bun-isolated-install");
for p in &g.pkgs {
let entry = format!("project/node_modules/.bun/{}/node_modules", p.store_key());
write_package(t, &format!("{entry}/{}", p.name), p, &mut rng)?;
for (d, v) in &p.deps {
let Some(dep) = g.resolve(p, d, v) else {
continue;
};
let up = "../".repeat(1 + d.matches('/').count());
let target = format!("{up}../{}/node_modules/{d}", dep.store_key());
t.symlink(&target, &format!("{entry}/{d}"))?;
}
if !p.is_nested() {
let up = "../".repeat(1 + p.name.matches('/').count());
t.symlink(
&format!("{up}{}/node_modules/{}", p.store_key(), p.name),
&format!("project/node_modules/.bun/node_modules/{}", p.name),
)?;
}
}
for p in g.direct() {
let up = "../".repeat(p.name.matches('/').count());
t.symlink(
&format!("{up}.bun/{}/node_modules/{}", p.store_key(), p.name),
&format!("project/node_modules/{}", p.name),
)?;
}
t.mkdir("home")?;
Ok(fixture(&g, g.patches(false), &["bun.lock"], &[]))
}

// ── vlt ────────────────────────────────────────────────────────────────

fn vlt_id(p: &Pkg) -> String {
Expand Down
Loading