mirror of
https://github.com/oven-sh/bun
synced 2026-02-15 13:22:07 +00:00
Get bunx tests to pass on Windows (#9729)
* Get bunx tests to pass on Windows * wip * WIP * wip * wip * ads * asdf * makeOpenPath * almost revert * fix build * enoent * fix bun install git repos * cleanup * use custom zig stdlib from submodule * update dockerfile to copy zig stdlib sources * fix dockerfile, update gitmodules * fix dockerfile * fix build * fix build * fix symlinkat * fix build * fix build * Remove usages of unreachable * Fixup * Fixup * wip * fixup * Fix one of the bugs * asd * Normalize BUN_INSTALL_CACHE_DIR var * Set iterable to false when we're about to delete * Update bun.zig * I still can't repro this outside CI * i think that fixes it? * fix posix compile * factor out directory creation * update all install methods to use InstallDirState * move walker creation to init function * fix error cleanup * fix posix compile * all install tests pass locally * cleanup * [autofix.ci] apply automated fixes * Fix posix regressions --------- Co-authored-by: Dylan Conway <dylan.conway567@gmail.com> Co-authored-by: Meghan Denny <hello@nektro.net> Co-authored-by: Georgijs Vilums <georgijs.vilums@gmail.com> Co-authored-by: Georgijs <48869301+gvilums@users.noreply.github.com> Co-authored-by: Georgijs Vilums <georgijs@bun.sh> Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
@@ -63,43 +63,19 @@ pub const BunxCommand = struct {
|
||||
const nanoseconds_cache_valid = seconds_cache_valid * 1000000000;
|
||||
|
||||
fn getBinNameFromSubpath(bundler: *bun.Bundler, dir_fd: bun.FileDescriptor, subpath_z: [:0]const u8) ![]const u8 {
|
||||
const target_package_json_fd = try std.os.openatZ(dir_fd.cast(), subpath_z, std.os.O.RDONLY, 0);
|
||||
const target_package_json = std.fs.File{ .handle = target_package_json_fd };
|
||||
|
||||
const is_stale = is_stale: {
|
||||
if (Environment.isWindows) {
|
||||
var io_status_block: std.os.windows.IO_STATUS_BLOCK = undefined;
|
||||
var info: std.os.windows.FILE_BASIC_INFORMATION = undefined;
|
||||
const rc = std.os.windows.ntdll.NtQueryInformationFile(target_package_json_fd, &io_status_block, &info, @sizeOf(std.os.windows.FILE_BASIC_INFORMATION), .FileBasicInformation);
|
||||
switch (rc) {
|
||||
.SUCCESS => {
|
||||
const time = std.os.windows.fromSysTime(info.LastWriteTime);
|
||||
const now = std.time.nanoTimestamp();
|
||||
break :is_stale (now - time > nanoseconds_cache_valid);
|
||||
},
|
||||
// treat failures to stat as stale
|
||||
else => break :is_stale true,
|
||||
}
|
||||
} else {
|
||||
var stat: std.os.Stat = undefined;
|
||||
const rc = std.c.fstat(target_package_json_fd, &stat);
|
||||
if (rc != 0) {
|
||||
break :is_stale true;
|
||||
}
|
||||
break :is_stale std.time.timestamp() - stat.mtime().tv_sec > seconds_cache_valid;
|
||||
}
|
||||
};
|
||||
|
||||
if (is_stale) {
|
||||
target_package_json.close();
|
||||
// If delete fails, oh well. Hope installation takes care of it.
|
||||
dir_fd.asDir().deleteTree(subpath_z) catch {};
|
||||
return error.NeedToInstall;
|
||||
}
|
||||
const target_package_json_fd = try bun.sys.openat(dir_fd, subpath_z, std.os.O.RDONLY, 0).unwrap();
|
||||
const target_package_json = bun.sys.File{ .handle = target_package_json_fd };
|
||||
|
||||
defer target_package_json.close();
|
||||
|
||||
const package_json_contents = try target_package_json.readToEndAlloc(bundler.allocator, std.math.maxInt(u32));
|
||||
const package_json_read = target_package_json.readToEnd(bundler.allocator);
|
||||
|
||||
// TODO: make this better
|
||||
if (package_json_read.err) |err| {
|
||||
try (bun.JSC.Maybe(void){ .err = err }).unwrap();
|
||||
}
|
||||
|
||||
const package_json_contents = package_json_read.bytes.items;
|
||||
const source = bun.logger.Source.initPathString(bun.span(subpath_z), package_json_contents);
|
||||
|
||||
bun.JSAst.Expr.Data.Store.create(default_allocator);
|
||||
@@ -134,9 +110,9 @@ pub const BunxCommand = struct {
|
||||
if (expr.asProperty("directories")) |dirs| {
|
||||
if (dirs.expr.asProperty("bin")) |bin_prop| {
|
||||
if (bin_prop.expr.asString(bundler.allocator)) |dir_name| {
|
||||
const bin_dir = try std.os.openat(dir_fd.cast(), dir_name, std.os.O.RDONLY, 0);
|
||||
defer std.os.close(bin_dir);
|
||||
const dir = std.fs.Dir{ .fd = bin_dir };
|
||||
const bin_dir = try bun.sys.openatA(dir_fd, dir_name, std.os.O.RDONLY | std.os.O.DIRECTORY, 0).unwrap();
|
||||
defer _ = bun.sys.close(bin_dir);
|
||||
const dir = std.fs.Dir{ .fd = bin_dir.cast() };
|
||||
var iterator = bun.DirIterator.iterate(dir, .u8);
|
||||
var entry = iterator.next();
|
||||
while (true) : (entry = iterator.next()) {
|
||||
@@ -159,17 +135,56 @@ pub const BunxCommand = struct {
|
||||
|
||||
fn getBinNameFromProjectDirectory(bundler: *bun.Bundler, dir_fd: bun.FileDescriptor, package_name: []const u8) ![]const u8 {
|
||||
var subpath: [bun.MAX_PATH_BYTES]u8 = undefined;
|
||||
const subpath_z = std.fmt.bufPrintZ(&subpath, "node_modules/{s}/package.json", .{package_name}) catch unreachable;
|
||||
const subpath_z = std.fmt.bufPrintZ(&subpath, bun.pathLiteral("node_modules/{s}/package.json"), .{package_name}) catch unreachable;
|
||||
return try getBinNameFromSubpath(bundler, dir_fd, subpath_z);
|
||||
}
|
||||
|
||||
fn getBinNameFromTempDirectory(bundler: *bun.Bundler, tempdir_name: []const u8, package_name: []const u8) ![]const u8 {
|
||||
fn getBinNameFromTempDirectory(bundler: *bun.Bundler, tempdir_name: []const u8, package_name: []const u8, with_stale_check: bool) ![]const u8 {
|
||||
var subpath: [bun.MAX_PATH_BYTES]u8 = undefined;
|
||||
if (with_stale_check) {
|
||||
const subpath_z = std.fmt.bufPrintZ(
|
||||
&subpath,
|
||||
bun.pathLiteral("{s}/package.json"),
|
||||
.{tempdir_name},
|
||||
) catch unreachable;
|
||||
const target_package_json_fd = bun.sys.openat(bun.toFD(std.fs.cwd().fd), subpath_z, std.os.O.RDONLY, 0).unwrap() catch return error.NeedToInstall;
|
||||
const target_package_json = bun.sys.File{ .handle = target_package_json_fd };
|
||||
|
||||
const is_stale = is_stale: {
|
||||
if (Environment.isWindows) {
|
||||
var io_status_block: std.os.windows.IO_STATUS_BLOCK = undefined;
|
||||
var info: std.os.windows.FILE_BASIC_INFORMATION = undefined;
|
||||
const rc = std.os.windows.ntdll.NtQueryInformationFile(target_package_json_fd.cast(), &io_status_block, &info, @sizeOf(std.os.windows.FILE_BASIC_INFORMATION), .FileBasicInformation);
|
||||
switch (rc) {
|
||||
.SUCCESS => {
|
||||
const time = std.os.windows.fromSysTime(info.LastWriteTime);
|
||||
const now = std.time.nanoTimestamp();
|
||||
break :is_stale (now - time > nanoseconds_cache_valid);
|
||||
},
|
||||
// treat failures to stat as stale
|
||||
else => break :is_stale true,
|
||||
}
|
||||
} else {
|
||||
const stat = target_package_json.stat().unwrap() catch break :is_stale true;
|
||||
break :is_stale std.time.timestamp() - stat.mtime().tv_sec > seconds_cache_valid;
|
||||
}
|
||||
};
|
||||
|
||||
if (is_stale) {
|
||||
_ = target_package_json.close();
|
||||
// If delete fails, oh well. Hope installation takes care of it.
|
||||
std.fs.cwd().deleteTree(tempdir_name) catch {};
|
||||
return error.NeedToInstall;
|
||||
}
|
||||
_ = target_package_json.close();
|
||||
}
|
||||
|
||||
const subpath_z = std.fmt.bufPrintZ(
|
||||
&subpath,
|
||||
"{s}/node_modules/{s}/package.json",
|
||||
bun.pathLiteral("{s}/node_modules/{s}/package.json"),
|
||||
.{ tempdir_name, package_name },
|
||||
) catch unreachable;
|
||||
|
||||
return try getBinNameFromSubpath(bundler, bun.toFD(std.fs.cwd().fd), subpath_z);
|
||||
}
|
||||
|
||||
@@ -182,7 +197,7 @@ pub const BunxCommand = struct {
|
||||
return error.NoBinFound;
|
||||
}
|
||||
|
||||
return getBinNameFromTempDirectory(bundler, tempdir_name, package_name) catch |err2| {
|
||||
return getBinNameFromTempDirectory(bundler, tempdir_name, package_name, true) catch |err2| {
|
||||
if (err2 == error.NoBinFound) {
|
||||
return error.NoBinFound;
|
||||
}
|
||||
@@ -520,7 +535,7 @@ pub const BunxCommand = struct {
|
||||
if (getBinName(&this_bundler, root_dir_fd, bunx_cache_dir, initial_bin_name)) |package_name_for_bin| {
|
||||
// if we check the bin name and its actually the same, we don't need to check $PATH here again
|
||||
if (!strings.eqlLong(package_name_for_bin, initial_bin_name, true)) {
|
||||
absolute_in_cache_dir = std.fmt.bufPrint(&absolute_in_cache_dir_buf, "{s}/node_modules/.bin/{s}{s}", .{ bunx_cache_dir, package_name_for_bin, bun.exe_suffix }) catch unreachable;
|
||||
absolute_in_cache_dir = std.fmt.bufPrint(&absolute_in_cache_dir_buf, bun.pathLiteral("{s}/node_modules/.bin/{s}{s}"), .{ bunx_cache_dir, package_name_for_bin, bun.exe_suffix }) catch unreachable;
|
||||
|
||||
// Only use the system-installed version if there is no version specified
|
||||
if (update_request.version.literal.isEmpty()) {
|
||||
@@ -559,7 +574,6 @@ pub const BunxCommand = struct {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const bunx_install_dir = try std.fs.cwd().makeOpenPath(bunx_cache_dir, .{});
|
||||
|
||||
create_package_json: {
|
||||
@@ -674,7 +688,7 @@ pub const BunxCommand = struct {
|
||||
}
|
||||
|
||||
// 2. The "bin" is possibly not the same as the package name, so we load the package.json to figure out what "bin" to use
|
||||
if (getBinNameFromTempDirectory(&this_bundler, bunx_cache_dir, result_package_name)) |package_name_for_bin| {
|
||||
if (getBinNameFromTempDirectory(&this_bundler, bunx_cache_dir, result_package_name, false)) |package_name_for_bin| {
|
||||
if (!strings.eqlLong(package_name_for_bin, initial_bin_name, true)) {
|
||||
absolute_in_cache_dir = std.fmt.bufPrint(&absolute_in_cache_dir_buf, "{s}/node_modules/.bin/{s}{s}", .{ bunx_cache_dir, package_name_for_bin, bun.exe_suffix }) catch unreachable;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user