Merge branch 'main' into ciro/fix-onclose

This commit is contained in:
Ciro Spaciari
2025-09-10 17:56:00 -07:00
committed by GitHub
4 changed files with 103 additions and 3 deletions

View File

@@ -4,7 +4,7 @@ register_repository(
REPOSITORY
HdrHistogram/HdrHistogram_c
COMMIT
8dcce8f68512fca460b171bccc3a5afce0048779
be60a9987ee48d0abf0d7b6a175bad8d6c1585d1
)
register_cmake_command(

View File

@@ -446,7 +446,6 @@ pub fn enqueueDependencyWithMainAndSuccessFn(
if (dependency.behavior.isOptionalPeer()) return;
var name = dependency.realname();
var name_hash = switch (dependency.version.tag) {
.dist_tag, .git, .github, .npm, .tarball, .workspace => String.Builder.stringHash(this.lockfile.str(&name)),
else => dependency.name_hash,

View File

@@ -120,7 +120,17 @@ fn extract(this: *const ExtractTarball, log: *logger.Log, tgz_bytes: []const u8)
};
const basename = brk: {
var tmp = name;
if (tmp[0] == '@') {
// Handle URLs - extract just the filename from the URL
if (strings.hasPrefixComptime(tmp, "https://") or strings.hasPrefixComptime(tmp, "http://")) {
tmp = std.fs.path.basename(tmp);
// Remove .tgz or .tar.gz extension if present
if (strings.endsWithComptime(tmp, ".tgz")) {
tmp = tmp[0 .. tmp.len - 4];
} else if (strings.endsWithComptime(tmp, ".tar.gz")) {
tmp = tmp[0 .. tmp.len - 7];
}
} else if (tmp[0] == '@') {
if (strings.indexOfChar(tmp, '/')) |i| {
tmp = tmp[i + 1 ..];
}

View File

@@ -2324,3 +2324,94 @@ it("should add multiple dependencies specified on command line", async () => {
});
await access(join(package_dir, "bun.lockb"));
});
it("should install tarball with tarball dependencies", async () => {
// This test verifies that tarballs containing dependencies that are also tarballs
// can be installed correctly. Regression test for URL corruption bug where
// URLs like https://example.com/pkg.tgz get mangled with cache folder patterns.
// Create simple test tarballs
const tmpDir = tmpdirSync();
// Create child package
const childDir = join(tmpDir, "child");
await mkdir(childDir, { recursive: true });
await writeFile(join(childDir, "package.json"), JSON.stringify({ name: "test-child", version: "1.0.0" }));
// Create child tarball
const { exited: childTarExited } = spawn({
cmd: ["tar", "-czf", join(tmpDir, "child.tgz"), "-C", tmpDir, "child"],
stdout: "pipe",
stderr: "pipe",
});
expect(await childTarExited).toBe(0);
// Set up server first to get the port
using server = Bun.serve({
port: 0,
fetch(req) {
const url = new URL(req.url);
if (url.pathname === "/child.tgz") {
return new Response(Bun.file(join(tmpDir, "child.tgz")));
} else if (url.pathname === "/parent.tgz") {
return new Response(Bun.file(join(tmpDir, "parent.tgz")));
}
return new Response("Not found", { status: 404 });
},
});
const server_url = server.url.href.replace(/\/+$/, "");
// Create parent package that depends on child via URL
const parentDir = join(tmpDir, "parent");
await mkdir(parentDir, { recursive: true });
await writeFile(
join(parentDir, "package.json"),
JSON.stringify({
name: "test-parent",
version: "1.0.0",
dependencies: {
"test-child": `${server_url}/child.tgz`,
},
}),
);
// Create parent tarball
const { exited: parentTarExited } = spawn({
cmd: ["tar", "-czf", join(tmpDir, "parent.tgz"), "-C", tmpDir, "parent"],
stdout: "pipe",
stderr: "pipe",
});
expect(await parentTarExited).toBe(0);
// Now test adding the parent tarball
await writeFile(
join(add_dir, "package.json"),
JSON.stringify({
name: "foo",
}),
);
const urls: string[] = [];
setHandler(dummyRegistry(urls));
const { stdout, stderr, exited } = spawn({
cmd: [bunExe(), "add", `${server_url}/parent.tgz`],
cwd: add_dir,
stdout: "pipe",
stdin: "pipe",
stderr: "pipe",
env,
});
const err = await new Response(stderr).text();
expect(err).not.toContain("error:");
expect(err).not.toContain("HttpNotFound");
expect(err).not.toContain("404");
expect(await exited).toBe(0);
// Verify both packages were installed
await access(join(add_dir, "node_modules", "test-parent"));
await access(join(add_dir, "node_modules", "test-child"));
});