diff options
-rw-r--r-- | src/c.zig | 9 | ||||
-rw-r--r-- | src/standalone_bun.zig | 6 | ||||
-rw-r--r-- | test/bundler/cli.test.ts | 41 |
3 files changed, 49 insertions, 7 deletions
@@ -116,7 +116,8 @@ pub fn moveFileZWithHandle(from_handle: std.os.fd_t, from_dir: std.os.fd_t, file std.os.renameatZ(from_dir, filename, to_dir, destination) catch |err| { switch (err) { error.RenameAcrossMountPoints => { - try moveFileZSlowWithHandle(from_handle, to_dir, destination); + try copyFileZSlowWithHandle(from_handle, to_dir, destination); + std.os.unlinkatZ(from_dir, filename, 0) catch {}; }, else => { return err; @@ -129,10 +130,12 @@ pub fn moveFileZWithHandle(from_handle: std.os.fd_t, from_dir: std.os.fd_t, file // macOS & BSDs will be slow because pub fn moveFileZSlow(from_dir: std.os.fd_t, filename: [*:0]const u8, to_dir: std.os.fd_t, destination: [*:0]const u8) !void { const in_handle = try std.os.openatZ(from_dir, filename, std.os.O.RDONLY | std.os.O.CLOEXEC, 0o600); - try moveFileZSlowWithHandle(in_handle, to_dir, destination); + defer std.os.close(in_handle); + try copyFileZSlowWithHandle(in_handle, to_dir, destination); + std.os.unlinkatZ(from_dir, filename, 0) catch {}; } -pub fn moveFileZSlowWithHandle(in_handle: std.os.fd_t, to_dir: std.os.fd_t, destination: [*:0]const u8) !void { +pub fn copyFileZSlowWithHandle(in_handle: std.os.fd_t, to_dir: std.os.fd_t, destination: [*:0]const u8) !void { const stat_ = try std.os.fstat(in_handle); // delete if exists, don't care if it fails. it may fail due to the file not existing // delete here because we run into weird truncation issues if we do not diff --git a/src/standalone_bun.zig b/src/standalone_bun.zig index 03cec9370..77cc92b15 100644 --- a/src/standalone_bun.zig +++ b/src/standalone_bun.zig @@ -257,7 +257,7 @@ pub const StandaloneModuleGraph = struct { // if we're on a mac, use clonefile() if we can // failure is okay, clonefile is just a fast path. if (Syscall.clonefile(self_exeZ, zname) == .result) { - switch (Syscall.open(zname, std.os.O.WRONLY | std.os.O.CLOEXEC, 0)) { + switch (Syscall.open(zname, std.os.O.RDWR | std.os.O.CLOEXEC, 0)) { .result => |res| break :brk res, .err => {}, } @@ -269,7 +269,7 @@ pub const StandaloneModuleGraph = struct { const fd = brk2: { var tried_changing_abs_dir = false; for (0..3) |retry| { - switch (Syscall.open(zname, std.os.O.CLOEXEC | std.os.O.WRONLY | std.os.O.CREAT, 0)) { + switch (Syscall.open(zname, std.os.O.CLOEXEC | std.os.O.RDWR | std.os.O.CREAT, 0)) { .result => |res| break :brk2 res, .err => |err| { if (retry < 2) { @@ -439,7 +439,7 @@ pub const StandaloneModuleGraph = struct { std.fs.cwd().fd, &(try std.os.toPosixPath(temp_location)), root_dir.dir.fd, - &(try std.os.toPosixPath(outfile)), + &(try std.os.toPosixPath(std.fs.path.basename(outfile))), ) catch |err| { if (err == error.IsDir) { Output.prettyErrorln("<r><red>error<r><d>:<r> {} is a directory. Please choose a different --outfile or delete the directory", .{bun.fmt.quote(outfile)}); diff --git a/test/bundler/cli.test.ts b/test/bundler/cli.test.ts index e2f99a9ed..3df2ab75e 100644 --- a/test/bundler/cli.test.ts +++ b/test/bundler/cli.test.ts @@ -1,6 +1,8 @@ import { bunEnv, bunExe } from "harness"; -import path from "path"; import { describe, expect, test } from "bun:test"; +import fs from "node:fs"; +import { tmpdir } from "node:os"; +import path from "node:path"; describe("bun build", () => { test("warnings dont return exit code 1", () => { @@ -13,4 +15,41 @@ describe("bun build", () => { 'warn: "key" prop before a {...spread} is deprecated in JSX. Falling back to classic runtime.', ); }); + + test("generating a standalone binary in nested path, issue #4195", () => { + function testCompile(outfile: string) { + const { exitCode } = Bun.spawnSync({ + cmd: [ + bunExe(), + "build", + path.join(import.meta.dir, "./fixtures/trivial/index.js"), + "--compile", + "--outfile", + outfile, + ], + env: bunEnv, + }); + expect(exitCode).toBe(0); + } + function testExec(outfile: string) { + const { exitCode } = Bun.spawnSync({ + cmd: [outfile], + }); + expect(exitCode).toBe(0); + } + { + const baseDir = `${tmpdir()}/bun-build-outfile-${Date.now()}`; + const outfile = path.join(baseDir, "index.exe"); + testCompile(outfile); + testExec(outfile); + fs.rmSync(baseDir, { recursive: true, force: true }); + } + { + const baseDir = `${tmpdir()}/bun-build-outfile2-${Date.now()}`; + const outfile = path.join(baseDir, "b/u/n", "index.exe"); + testCompile(outfile); + testExec(outfile); + fs.rmSync(baseDir, { recursive: true, force: true }); + } + }); }); |