mirror of
https://github.com/oven-sh/bun
synced 2026-02-04 07:58:54 +00:00
Compare commits
6 Commits
dylan/pyth
...
jarred/cra
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9e59e40abc | ||
|
|
5a72185685 | ||
|
|
94fa2020c1 | ||
|
|
ab420e1f9c | ||
|
|
e12e23fc55 | ||
|
|
c3f02df42f |
@@ -263,15 +263,18 @@ function getTestExpectations() {
|
||||
return expectations;
|
||||
}
|
||||
|
||||
const skipArray = (() => {
|
||||
const path = join(cwd, "test/no-validate-exceptions.txt");
|
||||
function normalizeFilePathTextFile(path) {
|
||||
if (!existsSync(path)) {
|
||||
return [];
|
||||
}
|
||||
return readFileSync(path, "utf-8")
|
||||
.split("\n")
|
||||
.filter(line => !line.startsWith("#") && line.length > 0);
|
||||
})();
|
||||
.filter(line => !line.startsWith("#") && line.length > 0)
|
||||
.map(line => line.replace(/\\/g, "/").trim());
|
||||
}
|
||||
|
||||
const skipArray = normalizeFilePathTextFile(join(cwd, "test/no-validate-exceptions.txt"));
|
||||
const noStackOverflowArray = normalizeFilePathTextFile(join(cwd, "test/stackoverflow-tests.txt"));
|
||||
|
||||
/**
|
||||
* Returns whether we should validate exception checks running the given test
|
||||
@@ -1026,7 +1029,7 @@ function getCombinedPath(execPath) {
|
||||
* @param {SpawnOptions} options
|
||||
* @returns {Promise<SpawnBunResult>}
|
||||
*/
|
||||
async function spawnBun(execPath, { args, cwd, timeout, env, stdout, stderr }) {
|
||||
async function spawnBun(execPath, { args, cwd, timeout, env, stdout, stderr, testPath }) {
|
||||
const path = getCombinedPath(execPath);
|
||||
const tmpdirPath = mkdtempSync(join(tmpdir(), "buntmp-"));
|
||||
const { username, homedir } = userInfo();
|
||||
@@ -1040,6 +1043,7 @@ async function spawnBun(execPath, { args, cwd, timeout, env, stdout, stderr }) {
|
||||
SHELL: shellPath,
|
||||
FORCE_COLOR: "1",
|
||||
BUN_FEATURE_FLAG_INTERNAL_FOR_TESTING: "1",
|
||||
BUN_FEATURE_FLAG_CRASH_ON_STACK_OVERFLOW: "1",
|
||||
BUN_DEBUG_QUIET_LOGS: "1",
|
||||
BUN_GARBAGE_COLLECTOR_LEVEL: "1",
|
||||
BUN_JSC_randomIntegrityAuditRate: "1.0",
|
||||
@@ -1052,6 +1056,12 @@ async function spawnBun(execPath, { args, cwd, timeout, env, stdout, stderr }) {
|
||||
: { BUN_ENABLE_CRASH_REPORTING: "0" }),
|
||||
};
|
||||
|
||||
if (testPath) {
|
||||
if (noStackOverflowArray.includes(testPath.replaceAll("\\", "/"))) {
|
||||
delete bunEnv.BUN_FEATURE_FLAG_CRASH_ON_STACK_OVERFLOW;
|
||||
}
|
||||
}
|
||||
|
||||
if (basename(execPath).includes("asan")) {
|
||||
bunEnv.ASAN_OPTIONS = "allow_user_segv_handler=1:disable_coredump=0";
|
||||
}
|
||||
@@ -1250,6 +1260,7 @@ async function spawnBunTest(execPath, testPath, options = { cwd }) {
|
||||
}
|
||||
|
||||
const { ok, error, stdout, crashes } = await spawnBun(execPath, {
|
||||
testPath,
|
||||
args: isReallyTest ? testArgs : [...args, absPath],
|
||||
cwd: options["cwd"],
|
||||
timeout: isReallyTest ? timeout : 30_000,
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
<asmv3:application>
|
||||
<asmv3:windowsSettings>
|
||||
<longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
|
||||
<heapType xmlns="http://schemas.microsoft.com/SMI/2020/WindowsSettings">SegmentHeap</heapType>
|
||||
</asmv3:windowsSettings>
|
||||
</asmv3:application>
|
||||
</assembly>
|
||||
@@ -141,6 +141,35 @@ pub const Run = struct {
|
||||
return bun.shell.Interpreter.initAndRunFromFile(ctx, mini, entry_path);
|
||||
}
|
||||
|
||||
fn resolveStdinEntryPath(ctx: Command.Context) !string {
|
||||
const trigger = bun.pathLiteral("/[stdin]");
|
||||
var entry_point_buf: [bun.MAX_PATH_BYTES + trigger.len]u8 = undefined;
|
||||
const cwd = try std.posix.getcwd(&entry_point_buf);
|
||||
@memcpy(entry_point_buf[cwd.len..][0..trigger.len], trigger);
|
||||
const entry_path = entry_point_buf[0 .. cwd.len + trigger.len];
|
||||
|
||||
var passthrough_list = try std.ArrayList(string).initCapacity(ctx.allocator, ctx.passthrough.len + 1);
|
||||
passthrough_list.appendAssumeCapacity("-");
|
||||
passthrough_list.appendSliceAssumeCapacity(ctx.passthrough);
|
||||
ctx.passthrough = passthrough_list.items;
|
||||
|
||||
return try bun.default_allocator.dupe(u8, entry_path);
|
||||
}
|
||||
|
||||
pub fn bootFromStdin(ctx: Command.Context) !void {
|
||||
var stdin_allocator = std.heap.stackFallback(2048, bun.default_allocator);
|
||||
var script = std.ArrayList(u8).init(stdin_allocator.get());
|
||||
_ = try bun.sys.File.readToEndWithArrayList(
|
||||
.{ .handle = bun.FD.stdin() },
|
||||
&script,
|
||||
.{ .probably_small = false, .allow_pread = false },
|
||||
).unwrap();
|
||||
|
||||
ctx.runtime_options.eval.script = script.items;
|
||||
|
||||
try Run.boot(ctx, try resolveStdinEntryPath(ctx), null);
|
||||
}
|
||||
|
||||
pub fn boot(ctx: Command.Context, entry_path: string, loader: ?bun.options.Loader) !void {
|
||||
jsc.markBinding(@src());
|
||||
|
||||
|
||||
@@ -4,6 +4,12 @@ pub const JSGlobalObject = opaque {
|
||||
}
|
||||
extern fn JSGlobalObject__throwStackOverflow(this: *JSGlobalObject) void;
|
||||
pub fn throwStackOverflow(this: *JSGlobalObject) void {
|
||||
if (comptime bun.Environment.is_canary) {
|
||||
if (bun.getRuntimeFeatureFlag(.BUN_FEATURE_FLAG_CRASH_ON_STACK_OVERFLOW)) {
|
||||
@panic("Stack overflow. If this was intentional, update test/stackoverflow-tests.txt");
|
||||
}
|
||||
}
|
||||
|
||||
JSGlobalObject__throwStackOverflow(this);
|
||||
}
|
||||
extern fn JSGlobalObject__throwOutOfMemoryError(this: *JSGlobalObject) void;
|
||||
|
||||
@@ -64,7 +64,7 @@ fn cpusImplLinux(globalThis: *jsc.JSGlobalObject) !jsc.JSValue {
|
||||
const file = try std.fs.openFileAbsolute("/proc/stat", .{});
|
||||
defer file.close();
|
||||
|
||||
const read = try bun.sys.File.from(file).readToEndWithArrayList(&file_buf, true).unwrap();
|
||||
const read = try bun.sys.File.from(file).readToEndWithArrayList(&file_buf, .{ .probably_small = true }).unwrap();
|
||||
defer file_buf.clearRetainingCapacity();
|
||||
const contents = file_buf.items[0..read];
|
||||
|
||||
@@ -104,7 +104,7 @@ fn cpusImplLinux(globalThis: *jsc.JSGlobalObject) !jsc.JSValue {
|
||||
if (std.fs.openFileAbsolute("/proc/cpuinfo", .{})) |file| {
|
||||
defer file.close();
|
||||
|
||||
const read = try bun.sys.File.from(file).readToEndWithArrayList(&file_buf, true).unwrap();
|
||||
const read = try bun.sys.File.from(file).readToEndWithArrayList(&file_buf, .{ .probably_small = true }).unwrap();
|
||||
defer file_buf.clearRetainingCapacity();
|
||||
const contents = file_buf.items[0..read];
|
||||
|
||||
@@ -155,7 +155,7 @@ fn cpusImplLinux(globalThis: *jsc.JSGlobalObject) !jsc.JSValue {
|
||||
if (std.fs.openFileAbsolute(path, .{})) |file| {
|
||||
defer file.close();
|
||||
|
||||
const read = try bun.sys.File.from(file).readToEndWithArrayList(&file_buf, true).unwrap();
|
||||
const read = try bun.sys.File.from(file).readToEndWithArrayList(&file_buf, .{ .probably_small = true }).unwrap();
|
||||
defer file_buf.clearRetainingCapacity();
|
||||
const contents = file_buf.items[0..read];
|
||||
|
||||
|
||||
@@ -3730,6 +3730,12 @@ pub const StackCheck = struct {
|
||||
// Workaround for lack of branch hints.
|
||||
pub noinline fn throwStackOverflow() StackOverflow!void {
|
||||
@branchHint(.cold);
|
||||
if (comptime bun.Environment.is_canary) {
|
||||
if (bun.getRuntimeFeatureFlag(.BUN_FEATURE_FLAG_CRASH_ON_STACK_OVERFLOW)) {
|
||||
@panic("Stack overflow. If this was intentional, update test/stackoverflow-tests.txt");
|
||||
}
|
||||
}
|
||||
|
||||
return error.StackOverflow;
|
||||
}
|
||||
const StackOverflow = error{StackOverflow};
|
||||
|
||||
@@ -1222,79 +1222,76 @@ pub const RunCommand = struct {
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
// This is split into another function to ensure we don't keep all this stack space used for the entire lifetime of the application.
|
||||
fn resolveAbsoluteScriptPath(script_name_to_search: string) !?string {
|
||||
var file_path = script_name_to_search;
|
||||
var script_name_buf: bun.PathBuffer = undefined;
|
||||
|
||||
const file = bun.FD.fromStdFile((brk: {
|
||||
// This whole scope should be refactored.
|
||||
if (std.fs.path.isAbsolute(script_name_to_search)) {
|
||||
const win_resolver = resolve_path.PosixToWinNormalizer.get();
|
||||
defer win_resolver.deinit();
|
||||
var resolved = win_resolver.resolveCWD(script_name_to_search) catch @panic("Could not resolve path");
|
||||
if (comptime Environment.isWindows) {
|
||||
resolved = resolve_path.normalizeString(resolved, false, .windows);
|
||||
}
|
||||
break :brk bun.openFile(
|
||||
resolved,
|
||||
.{ .mode = .read_only },
|
||||
);
|
||||
} else if (!strings.hasPrefix(script_name_to_search, "..") and script_name_to_search[0] != '~') {
|
||||
const file_pathZ = brk2: {
|
||||
@memcpy(script_name_buf[0..file_path.len], file_path);
|
||||
script_name_buf[file_path.len] = 0;
|
||||
break :brk2 script_name_buf[0..file_path.len :0];
|
||||
};
|
||||
|
||||
break :brk bun.openFileZ(file_pathZ, .{ .mode = .read_only });
|
||||
} else {
|
||||
var path_buf_2: bun.PathBuffer = undefined;
|
||||
const cwd = bun.getcwd(&path_buf_2) catch return null;
|
||||
path_buf_2[cwd.len] = std.fs.path.sep;
|
||||
var parts = [_]string{script_name_to_search};
|
||||
file_path = resolve_path.joinAbsStringBuf(
|
||||
path_buf_2[0 .. cwd.len + 1],
|
||||
&script_name_buf,
|
||||
&parts,
|
||||
.auto,
|
||||
);
|
||||
if (file_path.len == 0) return null;
|
||||
script_name_buf[file_path.len] = 0;
|
||||
const file_pathZ = script_name_buf[0..file_path.len :0];
|
||||
break :brk bun.openFileZ(file_pathZ, .{ .mode = .read_only });
|
||||
}
|
||||
}) catch return null).makeLibUVOwnedForSyscall(.open, .close_on_fail).unwrap() catch return null;
|
||||
defer file.close();
|
||||
|
||||
switch (bun.sys.fstat(file)) {
|
||||
.result => |stat| {
|
||||
// directories cannot be run. if only there was a faster way to check this
|
||||
if (bun.S.ISDIR(@intCast(stat.mode))) return null;
|
||||
},
|
||||
.err => return null,
|
||||
}
|
||||
|
||||
Global.configureAllocator(.{ .long_running = true });
|
||||
|
||||
return try bun.default_allocator.dupe(u8, try bun.getFdPath(file, &script_name_buf));
|
||||
}
|
||||
fn maybeOpenWithBunJS(ctx: Command.Context) bool {
|
||||
if (ctx.args.entry_points.len == 0)
|
||||
return false;
|
||||
var script_name_buf: bun.PathBuffer = undefined;
|
||||
|
||||
const script_name_to_search = ctx.args.entry_points[0];
|
||||
|
||||
var absolute_script_path: ?string = null;
|
||||
|
||||
// TODO: optimize this pass for Windows. we can make better use of system apis available
|
||||
var file_path = script_name_to_search;
|
||||
{
|
||||
const file = bun.FD.fromStdFile((brk: {
|
||||
if (std.fs.path.isAbsolute(script_name_to_search)) {
|
||||
var win_resolver = resolve_path.PosixToWinNormalizer{};
|
||||
var resolved = win_resolver.resolveCWD(script_name_to_search) catch @panic("Could not resolve path");
|
||||
if (comptime Environment.isWindows) {
|
||||
resolved = resolve_path.normalizeString(resolved, false, .windows);
|
||||
}
|
||||
break :brk bun.openFile(
|
||||
resolved,
|
||||
.{ .mode = .read_only },
|
||||
);
|
||||
} else if (!strings.hasPrefix(script_name_to_search, "..") and script_name_to_search[0] != '~') {
|
||||
const file_pathZ = brk2: {
|
||||
@memcpy(script_name_buf[0..file_path.len], file_path);
|
||||
script_name_buf[file_path.len] = 0;
|
||||
break :brk2 script_name_buf[0..file_path.len :0];
|
||||
};
|
||||
|
||||
break :brk bun.openFileZ(file_pathZ, .{ .mode = .read_only });
|
||||
} else {
|
||||
var path_buf_2: bun.PathBuffer = undefined;
|
||||
const cwd = bun.getcwd(&path_buf_2) catch return false;
|
||||
path_buf_2[cwd.len] = std.fs.path.sep;
|
||||
var parts = [_]string{script_name_to_search};
|
||||
file_path = resolve_path.joinAbsStringBuf(
|
||||
path_buf_2[0 .. cwd.len + 1],
|
||||
&script_name_buf,
|
||||
&parts,
|
||||
.auto,
|
||||
);
|
||||
if (file_path.len == 0) return false;
|
||||
script_name_buf[file_path.len] = 0;
|
||||
const file_pathZ = script_name_buf[0..file_path.len :0];
|
||||
break :brk bun.openFileZ(file_pathZ, .{ .mode = .read_only });
|
||||
}
|
||||
}) catch return false).makeLibUVOwnedForSyscall(.open, .close_on_fail).unwrap() catch return false;
|
||||
defer file.close();
|
||||
|
||||
switch (bun.sys.fstat(file)) {
|
||||
.result => |stat| {
|
||||
// directories cannot be run. if only there was a faster way to check this
|
||||
if (bun.S.ISDIR(@intCast(stat.mode))) return false;
|
||||
},
|
||||
.err => return false,
|
||||
}
|
||||
|
||||
Global.configureAllocator(.{ .long_running = true });
|
||||
|
||||
absolute_script_path = brk: {
|
||||
if (comptime !Environment.isWindows) break :brk bun.getFdPath(file, &script_name_buf) catch return false;
|
||||
|
||||
var fd_path_buf: bun.PathBuffer = undefined;
|
||||
break :brk bun.getFdPath(file, &fd_path_buf) catch return false;
|
||||
};
|
||||
}
|
||||
const absolute_script_path = (resolveAbsoluteScriptPath(script_name_to_search) catch null) orelse return false;
|
||||
|
||||
if (!ctx.debug.loaded_bunfig) {
|
||||
bun.cli.Arguments.loadConfigPath(ctx.allocator, true, "bunfig.toml", ctx, .RunCommand) catch {};
|
||||
}
|
||||
|
||||
_ = _bootAndHandleError(ctx, absolute_script_path.?, null);
|
||||
_ = _bootAndHandleError(ctx, absolute_script_path, null);
|
||||
return true;
|
||||
}
|
||||
pub fn exec(
|
||||
@@ -1373,26 +1370,7 @@ pub const RunCommand = struct {
|
||||
if (target_name.len == 1 and target_name[0] == '-') {
|
||||
log("Executing from stdin", .{});
|
||||
|
||||
// read from stdin
|
||||
var stack_fallback = std.heap.stackFallback(2048, bun.default_allocator);
|
||||
var list = std.ArrayList(u8).init(stack_fallback.get());
|
||||
errdefer list.deinit();
|
||||
|
||||
std.io.getStdIn().reader().readAllArrayList(&list, 1024 * 1024 * 1024) catch return false;
|
||||
ctx.runtime_options.eval.script = list.items;
|
||||
|
||||
const trigger = bun.pathLiteral("/[stdin]");
|
||||
var entry_point_buf: [bun.MAX_PATH_BYTES + trigger.len]u8 = undefined;
|
||||
const cwd = try std.posix.getcwd(&entry_point_buf);
|
||||
@memcpy(entry_point_buf[cwd.len..][0..trigger.len], trigger);
|
||||
const entry_path = entry_point_buf[0 .. cwd.len + trigger.len];
|
||||
|
||||
var passthrough_list = try std.ArrayList(string).initCapacity(ctx.allocator, ctx.passthrough.len + 1);
|
||||
passthrough_list.appendAssumeCapacity("-");
|
||||
passthrough_list.appendSliceAssumeCapacity(ctx.passthrough);
|
||||
ctx.passthrough = passthrough_list.items;
|
||||
|
||||
Run.boot(ctx, ctx.allocator.dupe(u8, entry_path) catch return false, null) catch |err| {
|
||||
Run.bootFromStdin(ctx) catch |err| {
|
||||
ctx.log.print(Output.errorWriter()) catch {};
|
||||
|
||||
Output.prettyErrorln("<r><red>error<r>: Failed to run <b>{s}<r> due to error <b>{s}<r>", .{
|
||||
@@ -1590,15 +1568,23 @@ pub const RunCommand = struct {
|
||||
return false;
|
||||
}
|
||||
|
||||
fn resolveEvalScriptPath() !string {
|
||||
const trigger = bun.pathLiteral("/[eval]");
|
||||
var entry_point_buf: [bun.MAX_PATH_BYTES + trigger.len]u8 = undefined;
|
||||
const cwd = try std.posix.getcwd(&entry_point_buf);
|
||||
@memcpy(entry_point_buf[cwd.len..][0..trigger.len], trigger);
|
||||
return try bun.default_allocator.dupe(u8, entry_point_buf[0 .. cwd.len + trigger.len]);
|
||||
}
|
||||
|
||||
fn execEvalScriptAsIfNode(ctx: Command.Context) !void {
|
||||
try Run.boot(ctx, try resolveEvalScriptPath(), null);
|
||||
}
|
||||
|
||||
pub fn execAsIfNode(ctx: Command.Context) !void {
|
||||
bun.assert(CLI.pretend_to_be_node);
|
||||
|
||||
if (ctx.runtime_options.eval.script.len > 0) {
|
||||
const trigger = bun.pathLiteral("/[eval]");
|
||||
var entry_point_buf: [bun.MAX_PATH_BYTES + trigger.len]u8 = undefined;
|
||||
const cwd = try std.posix.getcwd(&entry_point_buf);
|
||||
@memcpy(entry_point_buf[cwd.len..][0..trigger.len], trigger);
|
||||
try Run.boot(ctx, entry_point_buf[0 .. cwd.len + trigger.len], null);
|
||||
try execEvalScriptAsIfNode(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1607,16 +1593,9 @@ pub const RunCommand = struct {
|
||||
Global.exit(1);
|
||||
}
|
||||
|
||||
// TODO(@paperclover): merge windows branch
|
||||
// var win_resolver = resolve_path.PosixToWinNormalizer{};
|
||||
|
||||
const filename = ctx.positionals[0];
|
||||
|
||||
const normalized_filename = if (std.fs.path.isAbsolute(filename))
|
||||
// TODO(@paperclover): merge windows branch
|
||||
// try win_resolver.resolveCWD("/dev/bun/test/etc.js");
|
||||
filename
|
||||
else brk: {
|
||||
const normalized_filename = if (std.fs.path.isAbsolute(filename)) filename else brk: {
|
||||
const cwd = try bun.getcwd(&path_buf);
|
||||
path_buf[cwd.len] = std.fs.path.sep_posix;
|
||||
var parts = [_]string{filename};
|
||||
|
||||
@@ -40,6 +40,8 @@ pub const RuntimeFeatureFlag = enum {
|
||||
BUN_NO_CODESIGN_MACHO_BINARY,
|
||||
BUN_TRACE,
|
||||
NODE_NO_WARNINGS,
|
||||
|
||||
BUN_FEATURE_FLAG_CRASH_ON_STACK_OVERFLOW,
|
||||
};
|
||||
|
||||
/// Enable breaking changes for the next major release of Bun
|
||||
|
||||
@@ -539,7 +539,8 @@ var ensureTempNodeGypScriptOnce = bun.once(struct {
|
||||
fn httpThreadOnInitError(err: HTTP.InitError, opts: HTTP.HTTPThread.InitOpts) noreturn {
|
||||
switch (err) {
|
||||
error.LoadCAFile => {
|
||||
var normalizer: bun.path.PosixToWinNormalizer = .{};
|
||||
const normalizer = bun.path.PosixToWinNormalizer.get();
|
||||
defer normalizer.deinit();
|
||||
const normalized = normalizer.resolveZ(FileSystem.instance.top_level_dir, opts.abs_ca_file_name);
|
||||
if (!bun.sys.existsZ(normalized)) {
|
||||
Output.err("HTTPThread", "could not find CA file: '{s}'", .{opts.abs_ca_file_name});
|
||||
|
||||
@@ -162,25 +162,16 @@ pub fn openGlobalDir(explicit_global_dir: string) !std.fs.Dir {
|
||||
}
|
||||
|
||||
if (bun.getenvZ("BUN_INSTALL")) |home_dir| {
|
||||
var buf: bun.PathBuffer = undefined;
|
||||
var parts = [_]string{ "install", "global" };
|
||||
const path = Path.joinAbsStringBuf(home_dir, &buf, &parts, .auto);
|
||||
return try std.fs.cwd().makeOpenPath(path, .{});
|
||||
return try bun.path.makeOpen(home_dir, &.{ "install", "global" });
|
||||
}
|
||||
|
||||
if (!Environment.isWindows) {
|
||||
if (bun.getenvZ("XDG_CACHE_HOME") orelse bun.getenvZ("HOME")) |home_dir| {
|
||||
var buf: bun.PathBuffer = undefined;
|
||||
var parts = [_]string{ ".bun", "install", "global" };
|
||||
const path = Path.joinAbsStringBuf(home_dir, &buf, &parts, .auto);
|
||||
return try std.fs.cwd().makeOpenPath(path, .{});
|
||||
return try bun.path.makeOpen(home_dir, &.{ ".bun", "install", "global" });
|
||||
}
|
||||
} else {
|
||||
if (bun.getenvZ("USERPROFILE")) |home_dir| {
|
||||
var buf: bun.PathBuffer = undefined;
|
||||
var parts = [_]string{ ".bun", "install", "global" };
|
||||
const path = Path.joinAbsStringBuf(home_dir, &buf, &parts, .auto);
|
||||
return try std.fs.cwd().makeOpenPath(path, .{});
|
||||
return try bun.path.makeOpen(home_dir, &.{ ".bun", "install", "global" });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,22 +192,11 @@ pub fn openGlobalBinDir(opts_: ?*const Api.BunInstall) !std.fs.Dir {
|
||||
}
|
||||
|
||||
if (bun.getenvZ("BUN_INSTALL")) |home_dir| {
|
||||
var buf: bun.PathBuffer = undefined;
|
||||
var parts = [_]string{
|
||||
"bin",
|
||||
};
|
||||
const path = Path.joinAbsStringBuf(home_dir, &buf, &parts, .auto);
|
||||
return try std.fs.cwd().makeOpenPath(path, .{});
|
||||
return try bun.path.makeOpen(home_dir, &.{"bin"});
|
||||
}
|
||||
|
||||
if (bun.getenvZ("XDG_CACHE_HOME") orelse bun.getenvZ(bun.DotEnv.home_env)) |home_dir| {
|
||||
var buf: bun.PathBuffer = undefined;
|
||||
var parts = [_]string{
|
||||
".bun",
|
||||
"bin",
|
||||
};
|
||||
const path = Path.joinAbsStringBuf(home_dir, &buf, &parts, .auto);
|
||||
return try std.fs.cwd().makeOpenPath(path, .{});
|
||||
return try bun.path.makeOpen(home_dir, &.{ ".bun", "bin" });
|
||||
}
|
||||
|
||||
return error.@"Missing global bin directory: try setting $BUN_INSTALL";
|
||||
@@ -699,7 +679,6 @@ const Environment = bun.Environment;
|
||||
const FD = bun.FD;
|
||||
const OOM = bun.OOM;
|
||||
const Output = bun.Output;
|
||||
const Path = bun.path;
|
||||
const URL = bun.URL;
|
||||
const logger = bun.logger;
|
||||
const strings = bun.strings;
|
||||
|
||||
@@ -194,7 +194,7 @@ pub const FolderResolution = union(Tag) {
|
||||
body.data.reset();
|
||||
var man = body.data.list.toManaged(manager.allocator);
|
||||
defer body.data.list = man.moveToUnmanaged();
|
||||
_ = try file.readToEndWithArrayList(&man, true).unwrap();
|
||||
_ = try file.readToEndWithArrayList(&man, .{ .probably_small = true }).unwrap();
|
||||
}
|
||||
|
||||
break :brk logger.Source.initPathString(abs, body.data.list.items);
|
||||
|
||||
@@ -198,7 +198,7 @@ const PosixBufferedReader = struct {
|
||||
pub fn finalBuffer(this: *PosixBufferedReader) *std.ArrayList(u8) {
|
||||
if (this.flags.memfd and this.handle == .fd) {
|
||||
defer this.handle.close(null, {});
|
||||
_ = bun.sys.File.readToEndWithArrayList(.{ .handle = this.handle.fd }, this.buffer(), false).unwrap() catch |err| {
|
||||
_ = bun.sys.File.readToEndWithArrayList(.{ .handle = this.handle.fd }, this.buffer(), .{ .probably_small = false, .allow_pread = false }).unwrap() catch |err| {
|
||||
bun.Output.debugWarn("error reading from memfd\n{}", .{err});
|
||||
return this.buffer();
|
||||
};
|
||||
|
||||
@@ -1825,46 +1825,56 @@ pub fn nextDirname(path_: []const u8) ?[]const u8 {
|
||||
///
|
||||
/// This API does nothing on Linux (it has a size of zero)
|
||||
pub const PosixToWinNormalizer = struct {
|
||||
const Buf = if (bun.Environment.isWindows) bun.PathBuffer else void;
|
||||
const Buf = if (bun.Environment.isWindows) *bun.PathBuffer else void;
|
||||
|
||||
_raw_bytes: Buf = undefined,
|
||||
_raw_bytes: Buf,
|
||||
|
||||
pub inline fn get() PosixToWinNormalizer {
|
||||
if (comptime bun.Environment.isWindows) {
|
||||
return .{
|
||||
._raw_bytes = bun.path_buffer_pool.get(),
|
||||
};
|
||||
}
|
||||
return .{
|
||||
._raw_bytes = {},
|
||||
};
|
||||
}
|
||||
|
||||
pub inline fn deinit(this: PosixToWinNormalizer) void {
|
||||
if (comptime bun.Environment.isWindows) {
|
||||
bun.path_buffer_pool.put(this._raw_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
// methods on PosixToWinNormalizer, to be minimal yet stack allocate the PathBuffer
|
||||
// these do not force inline of much code
|
||||
pub inline fn resolve(
|
||||
this: *PosixToWinNormalizer,
|
||||
this: PosixToWinNormalizer,
|
||||
source_dir: []const u8,
|
||||
maybe_posix_path: []const u8,
|
||||
) []const u8 {
|
||||
return resolveWithExternalBuf(&this._raw_bytes, source_dir, maybe_posix_path);
|
||||
return resolveWithExternalBuf(this._raw_bytes, source_dir, maybe_posix_path);
|
||||
}
|
||||
|
||||
pub inline fn resolveZ(
|
||||
this: *PosixToWinNormalizer,
|
||||
this: PosixToWinNormalizer,
|
||||
source_dir: []const u8,
|
||||
maybe_posix_path: [:0]const u8,
|
||||
) [:0]const u8 {
|
||||
return resolveWithExternalBufZ(&this._raw_bytes, source_dir, maybe_posix_path);
|
||||
return resolveWithExternalBufZ(this._raw_bytes, source_dir, maybe_posix_path);
|
||||
}
|
||||
|
||||
pub inline fn resolveCWD(
|
||||
this: *PosixToWinNormalizer,
|
||||
this: PosixToWinNormalizer,
|
||||
maybe_posix_path: []const u8,
|
||||
) ![]const u8 {
|
||||
return resolveCWDWithExternalBuf(&this._raw_bytes, maybe_posix_path);
|
||||
}
|
||||
|
||||
pub inline fn resolveCWDZ(
|
||||
this: *PosixToWinNormalizer,
|
||||
maybe_posix_path: []const u8,
|
||||
) ![:0]const u8 {
|
||||
return resolveCWDWithExternalBufZ(&this._raw_bytes, maybe_posix_path);
|
||||
return resolveCWDWithExternalBuf(this._raw_bytes, maybe_posix_path);
|
||||
}
|
||||
|
||||
// underlying implementation:
|
||||
|
||||
fn resolveWithExternalBuf(
|
||||
buf: *Buf,
|
||||
buf: Buf,
|
||||
source_dir: []const u8,
|
||||
maybe_posix_path: []const u8,
|
||||
) []const u8 {
|
||||
@@ -1889,7 +1899,7 @@ pub const PosixToWinNormalizer = struct {
|
||||
}
|
||||
|
||||
fn resolveWithExternalBufZ(
|
||||
buf: *Buf,
|
||||
buf: Buf,
|
||||
source_dir: []const u8,
|
||||
maybe_posix_path: [:0]const u8,
|
||||
) [:0]const u8 {
|
||||
@@ -1915,7 +1925,7 @@ pub const PosixToWinNormalizer = struct {
|
||||
}
|
||||
|
||||
pub fn resolveCWDWithExternalBuf(
|
||||
buf: *Buf,
|
||||
buf: Buf,
|
||||
maybe_posix_path: []const u8,
|
||||
) ![]const u8 {
|
||||
assert(std.fs.path.isAbsoluteWindows(maybe_posix_path));
|
||||
@@ -2056,6 +2066,12 @@ pub fn posixToPlatformInPlace(comptime T: type, path_buffer: []T) void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn makeOpen(cwd: []const u8, parts: []const []const u8) !std.fs.Dir {
|
||||
var buf: bun.PathBuffer = undefined;
|
||||
const path = joinAbsStringBuf(cwd, &buf, parts, .auto);
|
||||
return try std.fs.cwd().makeOpenPath(path, .{});
|
||||
}
|
||||
|
||||
const Fs = @import("../fs.zig");
|
||||
const std = @import("std");
|
||||
|
||||
|
||||
@@ -761,7 +761,8 @@ pub const Resolver = struct {
|
||||
// It's always relative to the current working directory of the project root.
|
||||
//
|
||||
// ...unless you pass a relative path that exists in the standalone module graph executable.
|
||||
var source_dir_resolver: bun.path.PosixToWinNormalizer = .{};
|
||||
const source_dir_resolver: bun.path.PosixToWinNormalizer = bun.path.PosixToWinNormalizer.get();
|
||||
defer source_dir_resolver.deinit();
|
||||
const source_dir_normalized = brk: {
|
||||
if (r.standalone_module_graph) |graph| {
|
||||
if (bun.StandaloneModuleGraph.isBunStandaloneFilePath(import_path)) {
|
||||
@@ -986,9 +987,10 @@ pub const Resolver = struct {
|
||||
}
|
||||
} else if (dir.abs_real_path.len > 0) {
|
||||
var parts = [_]string{ dir.abs_real_path, query.entry.base() };
|
||||
var buf: bun.PathBuffer = undefined;
|
||||
var buf = bun.path_buffer_pool.get();
|
||||
defer bun.path_buffer_pool.put(buf);
|
||||
|
||||
var out = r.fs.absBuf(&parts, &buf);
|
||||
var out = r.fs.absBuf(&parts, buf);
|
||||
|
||||
const store_fd = r.store_fd;
|
||||
|
||||
@@ -1002,7 +1004,7 @@ pub const Resolver = struct {
|
||||
|
||||
if (!store_fd) {
|
||||
assert(file.stdioTag() == null);
|
||||
out = try file.getFdPath(&buf);
|
||||
out = try file.getFdPath(buf);
|
||||
file.close();
|
||||
query.entry.cache.fd = .invalid;
|
||||
} else {
|
||||
@@ -1014,15 +1016,14 @@ pub const Resolver = struct {
|
||||
defer {
|
||||
if (r.fs.fs.needToCloseFiles()) {
|
||||
if (query.entry.cache.fd.isValid()) {
|
||||
var file = query.entry.cache.fd.stdFile();
|
||||
file.close();
|
||||
query.entry.cache.fd.close();
|
||||
query.entry.cache.fd = .invalid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (store_fd) {
|
||||
out = try bun.getFdPath(query.entry.cache.fd, &buf);
|
||||
out = try bun.getFdPath(query.entry.cache.fd, buf);
|
||||
}
|
||||
|
||||
const symlink = try Fs.FileSystem.FilenameStore.instance.append(@TypeOf(out), out);
|
||||
@@ -1140,21 +1141,22 @@ pub const Resolver = struct {
|
||||
}
|
||||
|
||||
// Run node's resolution rules (e.g. adding ".js")
|
||||
var normalizer = ResolvePath.PosixToWinNormalizer{};
|
||||
if (r.loadAsFileOrDirectory(normalizer.resolve(source_dir, import_path), kind)) |entry| {
|
||||
return .{
|
||||
.success = Result{
|
||||
.dirname_fd = entry.dirname_fd,
|
||||
.path_pair = entry.path_pair,
|
||||
.diff_case = entry.diff_case,
|
||||
.package_json = entry.package_json,
|
||||
.file_fd = entry.file_fd,
|
||||
.jsx = r.opts.jsx,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return .{ .not_found = {} };
|
||||
const normalizer = ResolvePath.PosixToWinNormalizer.get();
|
||||
defer normalizer.deinit();
|
||||
const entry = r.loadAsFileOrDirectory(
|
||||
normalizer.resolve(source_dir, import_path),
|
||||
kind,
|
||||
) orelse return .{ .not_found = {} };
|
||||
return .{
|
||||
.success = Result{
|
||||
.dirname_fd = entry.dirname_fd,
|
||||
.path_pair = entry.path_pair,
|
||||
.diff_case = entry.diff_case,
|
||||
.package_json = entry.package_json,
|
||||
.file_fd = entry.file_fd,
|
||||
.jsx = r.opts.jsx,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// Check both relative and package paths for CSS URL tokens, with relative
|
||||
@@ -1287,6 +1289,7 @@ pub const Resolver = struct {
|
||||
|
||||
pub fn checkRelativePath(r: *ThisResolver, source_dir: string, import_path: string, kind: ast.ImportKind, global_cache: GlobalCache) Result.Union {
|
||||
const parts = [_]string{ source_dir, import_path };
|
||||
|
||||
const abs_path = r.fs.absBuf(&parts, bufs(.relative_abs_path));
|
||||
|
||||
if (r.opts.external.abs_paths.count() > 0 and r.opts.external.abs_paths.contains(abs_path)) {
|
||||
|
||||
@@ -533,17 +533,9 @@ pub const Mapping = struct {
|
||||
return null;
|
||||
|
||||
const name = source_map.external_source_names[@intCast(index)];
|
||||
|
||||
var buf: bun.PathBuffer = undefined;
|
||||
const normalized = bun.path.joinAbsStringBufZ(
|
||||
bun.path.dirname(base_filename, .auto),
|
||||
&buf,
|
||||
&.{name},
|
||||
.loose,
|
||||
);
|
||||
switch (bun.sys.File.readFrom(
|
||||
switch (bun.sys.File.readFromJoinedPath(
|
||||
std.fs.cwd(),
|
||||
normalized,
|
||||
&.{ bun.path.dirname(base_filename, .auto), name },
|
||||
bun.default_allocator,
|
||||
)) {
|
||||
.result => |r| break :bytes r,
|
||||
|
||||
42
src/sys.zig
42
src/sys.zig
@@ -4280,8 +4280,18 @@ pub const File = struct {
|
||||
return .{ .result = buf[0..read_amount] };
|
||||
}
|
||||
|
||||
pub fn readToEndWithArrayList(this: File, list: *std.ArrayList(u8), probably_small: bool) Maybe(usize) {
|
||||
if (probably_small) {
|
||||
pub const ReadToEndWithArrayListOptions = packed struct(u8) {
|
||||
probably_small: bool = false,
|
||||
allow_pread: bool = true,
|
||||
_padding: u6 = 0,
|
||||
};
|
||||
|
||||
pub fn readToEndWithArrayList(
|
||||
this: File,
|
||||
list: *std.ArrayList(u8),
|
||||
opts: ReadToEndWithArrayListOptions,
|
||||
) Maybe(usize) {
|
||||
if (opts.probably_small) {
|
||||
list.ensureUnusedCapacity(64) catch bun.outOfMemory();
|
||||
} else {
|
||||
list.ensureTotalCapacityPrecise(
|
||||
@@ -4300,7 +4310,7 @@ pub const File = struct {
|
||||
list.ensureUnusedCapacity(16) catch bun.outOfMemory();
|
||||
}
|
||||
|
||||
switch (if (comptime Environment.isPosix)
|
||||
switch (if ((comptime Environment.isPosix) and opts.allow_pread)
|
||||
pread(this.handle, list.unusedCapacitySlice(), total)
|
||||
else
|
||||
sys.read(this.handle, list.unusedCapacitySlice())) {
|
||||
@@ -4325,7 +4335,7 @@ pub const File = struct {
|
||||
/// Calls fstat() on the file to get the size of the file and avoids reallocations + extra read() calls.
|
||||
pub fn readToEnd(this: File, allocator: std.mem.Allocator) ReadToEndResult {
|
||||
var list = std.ArrayList(u8).init(allocator);
|
||||
return switch (readToEndWithArrayList(this, &list, false)) {
|
||||
return switch (readToEndWithArrayList(this, &list, .{ .probably_small = false })) {
|
||||
.err => |err| .{ .err = err, .bytes = list },
|
||||
.result => .{ .err = null, .bytes = list },
|
||||
};
|
||||
@@ -4335,7 +4345,7 @@ pub const File = struct {
|
||||
/// This will skip the fstat() call, preallocating 64 bytes instead of the file's size.
|
||||
pub fn readToEndSmall(this: File, allocator: std.mem.Allocator) ReadToEndResult {
|
||||
var list = std.ArrayList(u8).init(allocator);
|
||||
return switch (readToEndWithArrayList(this, &list, true)) {
|
||||
return switch (readToEndWithArrayList(this, &list, .{ .probably_small = true })) {
|
||||
.err => |err| .{ .err = err, .bytes = list },
|
||||
.result => .{ .err = null, .bytes = list },
|
||||
};
|
||||
@@ -4414,6 +4424,28 @@ pub const File = struct {
|
||||
return .{ .result = bytes };
|
||||
}
|
||||
|
||||
pub fn readFromJoinedPath(dir_fd: anytype, path_parts: []const []const u8, allocator: std.mem.Allocator) Maybe([]u8) {
|
||||
const path = bun.path_buffer_pool.get();
|
||||
defer bun.path_buffer_pool.put(path);
|
||||
|
||||
const file, const bytes = switch (readFileFrom(
|
||||
dir_fd,
|
||||
bun.path.joinAbsStringBufZ(
|
||||
if (path_parts.len > 0 and std.fs.path.isAbsolute(path_parts[0])) path_parts[0] else bun.fs.FileSystem.instance.top_level_dir,
|
||||
path,
|
||||
path_parts,
|
||||
.auto,
|
||||
),
|
||||
allocator,
|
||||
)) {
|
||||
.err => |err| return .{ .err = err },
|
||||
.result => |result| result,
|
||||
};
|
||||
|
||||
file.close();
|
||||
return .{ .result = bytes };
|
||||
}
|
||||
|
||||
const ToSourceOptions = struct {
|
||||
convert_bom: bool = false,
|
||||
};
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
"!= allocator.ptr": 0,
|
||||
".arguments_old(": 280,
|
||||
".stdDir()": 40,
|
||||
".stdFile()": 18,
|
||||
".stdFile()": 17,
|
||||
"// autofix": 168,
|
||||
": [a-zA-Z0-9_\\.\\*\\?\\[\\]\\(\\)]+ = undefined,": 229,
|
||||
": [a-zA-Z0-9_\\.\\*\\?\\[\\]\\(\\)]+ = undefined,": 228,
|
||||
"== alloc.ptr": 0,
|
||||
"== allocator.ptr": 0,
|
||||
"@import(\"bun\").": 0,
|
||||
@@ -30,7 +30,7 @@
|
||||
"std.enums.tagName(": 2,
|
||||
"std.fs.Dir": 170,
|
||||
"std.fs.File": 62,
|
||||
"std.fs.cwd": 103,
|
||||
"std.fs.cwd": 99,
|
||||
"std.log": 1,
|
||||
"std.mem.indexOfAny(u8": 0,
|
||||
"std.unicode": 30,
|
||||
|
||||
Reference in New Issue
Block a user