From 91cfd614cae695c399dc59b5aa138180aa38677d Mon Sep 17 00:00:00 2001 From: dave caruso Date: Wed, 31 Jan 2024 22:37:03 -0800 Subject: [PATCH] fix(window): some more bin things (#8612) * allow linking bins that do not exist. * fix some things --- src/cli.zig | 128 +++++++++++---------- src/cli/run_command.zig | 9 +- src/install/windows-shim/bun_shim_impl.exe | Bin 10752 -> 10752 bytes src/install/windows-shim/bun_shim_impl.zig | 8 +- src/string_immutable.zig | 7 ++ 5 files changed, 88 insertions(+), 64 deletions(-) diff --git a/src/cli.zig b/src/cli.zig index 0bb6dbf966..a6e1791b93 100644 --- a/src/cli.zig +++ b/src/cli.zig @@ -1168,15 +1168,12 @@ pub const Command = struct { } }; - const exe_suffix = if (Environment.isWindows) ".exe" else ""; - pub fn isBunX(argv0: []const u8) bool { - return strings.endsWithComptime(argv0, "bunx" ++ exe_suffix) or - (Environment.isDebug and strings.endsWithComptime(argv0, "bunx-debug" ++ exe_suffix)); + return strings.endsWithComptime(argv0, "bunx") or (Environment.isDebug and strings.endsWithComptime(argv0, "bunx-debug")); } pub fn isNode(argv0: []const u8) bool { - return strings.endsWithComptime(argv0, "node" ++ exe_suffix); + return strings.endsWithComptime(argv0, "node"); } pub fn which() Tag { @@ -1184,10 +1181,15 @@ pub const Command = struct { const argv0 = args_iter.next() orelse return .HelpCommand; - // symlink is argv[0] - if (isBunX(argv0)) return .BunxCommand; + const without_exe = if (Environment.isWindows) + strings.withoutSuffixComptime(argv0, ".exe") + else + argv0; - if (isNode(argv0)) { + // symlink is argv[0] + if (isBunX(without_exe)) return .BunxCommand; + + if (isNode(without_exe)) { @import("./deps/zig-clap/clap/streaming.zig").warn_on_unrecognized_flag = false; pretend_to_be_node = true; return .RunAsNodeCommand; @@ -1626,7 +1628,7 @@ pub const Command = struct { const ctx = try Command.Context.create(allocator, log, .RunCommand); if (ctx.positionals.len > 0) { - if (try RunCommand.exec(ctx, false, true)) { + if (try RunCommand.exec(ctx, false, true, false)) { return; } @@ -1743,7 +1745,7 @@ pub const Command = struct { } if (ctx.positionals.len > 0 and extension.len == 0) { - if (try RunCommand.exec(ctx, true, false)) { + if (try RunCommand.exec(ctx, true, false, true)) { return; } @@ -1789,61 +1791,71 @@ pub const Command = struct { 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_: anyerror!std.fs.File = brk: { - if (std.fs.path.isAbsoluteWindows(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, true, .windows); - } - absolute_script_path = resolved; - 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); + { + const file = bun.toLibUVOwnedFD(((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, true, .windows); + } + absolute_script_path = resolved; + 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: [bun.MAX_PATH_BYTES]u8 = undefined; + const cwd = bun.getcwd(&path_buf) catch return false; + path_buf[cwd.len] = std.fs.path.sep; + var parts = [_]string{script_name_to_search}; + file_path = resolve_path.joinAbsStringBuf( + path_buf[0 .. cwd.len + 1], + &script_name_buf, + &parts, + .auto, + ); + if (file_path.len == 0) return false; script_name_buf[file_path.len] = 0; - break :brk2 script_name_buf[0..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).handle); + defer _ = bun.sys.close(file); - break :brk bun.openFileZ(file_pathZ, .{ .mode = .read_only }); - } else { - var path_buf: [bun.MAX_PATH_BYTES]u8 = undefined; - const cwd = bun.getcwd(&path_buf) catch return false; - path_buf[cwd.len] = std.fs.path.sep; - var parts = [_]string{script_name_to_search}; - file_path = resolve_path.joinAbsStringBuf( - path_buf[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 }); + 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, } - }; - const file = file_ catch return false; + Global.configureAllocator(.{ .long_running = true }); - Global.configureAllocator(.{ .long_running = true }); + // the case where this doesn't work is if the script name on disk doesn't end with a known JS-like file extension + absolute_script_path = absolute_script_path orelse brk: { + if (comptime !Environment.isWindows) break :brk bun.getFdPath(file, &script_name_buf) catch return false; - // the case where this doesn't work is if the script name on disk doesn't end with a known JS-like file extension - absolute_script_path = absolute_script_path orelse brk: { - if (comptime !Environment.isWindows) break :brk bun.getFdPath(file.handle, &script_name_buf) catch return false; - - var fd_path_buf: bun.PathBuffer = undefined; - const path = bun.getFdPath(file.handle, &fd_path_buf) catch return false; - break :brk resolve_path.normalizeString( - resolve_path.PosixToWinNormalizer.resolveCWDWithExternalBufZ(&script_name_buf, path) catch @panic("Could not resolve path"), - true, - .windows, - ); - }; + var fd_path_buf: bun.PathBuffer = undefined; + const path = bun.getFdPath(file, &fd_path_buf) catch return false; + break :brk resolve_path.normalizeString( + resolve_path.PosixToWinNormalizer.resolveCWDWithExternalBufZ(&script_name_buf, path) catch @panic("Could not resolve path"), + true, + .windows, + ); + }; + } if (!ctx.debug.loaded_bunfig) { bun.CLI.Arguments.loadConfigPath(ctx.allocator, true, "bunfig.toml", ctx, .RunCommand) catch {}; diff --git a/src/cli/run_command.zig b/src/cli/run_command.zig index 3466b2e10f..963500fcb1 100644 --- a/src/cli/run_command.zig +++ b/src/cli/run_command.zig @@ -1098,7 +1098,12 @@ pub const RunCommand = struct { } } - pub fn exec(ctx_: Command.Context, comptime bin_dirs_only: bool, comptime log_errors: bool) !bool { + pub fn exec( + ctx_: Command.Context, + comptime bin_dirs_only: bool, + comptime log_errors: bool, + comptime did_try_open_with_bun_js: bool, + ) !bool { var ctx = ctx_; // Step 1. Figure out what we're trying to run var positionals = ctx.positionals; @@ -1138,7 +1143,7 @@ pub const RunCommand = struct { return true; } - if (log_errors or force_using_bun) { + if (!did_try_open_with_bun_js and (log_errors or force_using_bun)) { if (script_name_to_search.len > 0) { possibly_open_with_bun_js: { const ext = std.fs.path.extension(script_name_to_search); diff --git a/src/install/windows-shim/bun_shim_impl.exe b/src/install/windows-shim/bun_shim_impl.exe index e2e560b5d03ff04d1bc2dd73e69e0bdff2fe582c..5a81cbcafbc4b88ed611e48686e5e89f1ead917d 100755 GIT binary patch delta 562 zcmZn&X$YCn!2DQk_r_*cMn<*Gos2V?7_BBNvxGAWO|E9y#TY)>jP*NX{$xEi1xCHe z{%qb%pI9f)VcTX}#m2zUdVs$*myvK+b2vwx^)#u(g4VO zu^PnMHo2X>h&vd>i~|vwlUX?Yc#As^c=fs{@OfC?C{3Rn&moy4!U8nT>3EBZMd32YkBzSgy zcyS4+#FO#+%f~>e7h4$^7(BXrR2qQvuKz&r!g=z24oRDzKx<&)FKVEi4xpkJ`9My$ zk4nsoWk81Gw__}&Tra9Y64O9LB9Pc@&zZ`|n6Y^&mnCDp9tY5%WR^w`#uNV^c=WOc zYBDe!2GUs|dKZvj0CMECKpbfZXA)RO4#HUoRUQMSFM}l|Ad*2~ZK@Cs3z#DX;mCqH zN(>CFAmeK`C-E3CN_>)JU^oK@|5aZ>`IEbNEhcZ`HJJQ~S8ua7-&V%S0esTBx4-}Y nFZAR8{~th_6-Yk@(n>(u6NsgNI1GsOf%r90+-9?`z-37Q+GEih delta 593 zcmZn&X$YCnz`W`3u8qyCjErWRI~iv(F?vl_W(j9hnq1AYi!pt&8S8h(`pJ513XFD> z{n@;knAj%IVcTZf#m2zUdVs&Rh>?Ne#abXIt@#HNf6FEymw)>K+b2vwx^+EB(gDbP zu^YrXHo2X>h&vg?%mWdXlUX?Ycq=*&c=fs{@OfC?D9xE1&mmc_!U8nT>3EBZMWSD$9A9{5D^6mWb;y*J3gD>Orh8mR!piRI2{{QdO`O~BGlSg-n zN`hzShZpxi3VLnIU)}@Cy*R+Yz~Ir{qtXDRcl`%~7k;b^498tmV*Vq^c=U#-#CW`5 z0ZPFXzi0=#2E^$As(VodbR1eTG5 za3(^P`#|Z#U`Yvxq!U=1DunX|EF%Ts@PcKO7#LVV#^-Df;xS;HyolFe@*`e_$)9-b z#Qv);l4M{w0|)c0N||G(0Y|Nl9FSQLmq1NlZkIueMrfH)0^?Sc3= MP~2y;uE1qU0JX~4z5oCK diff --git a/src/install/windows-shim/bun_shim_impl.zig b/src/install/windows-shim/bun_shim_impl.zig index ef918cfc72..278beeef27 100644 --- a/src/install/windows-shim/bun_shim_impl.zig +++ b/src/install/windows-shim/bun_shim_impl.zig @@ -609,9 +609,9 @@ fn launcher(bun_ctx: anytype) noreturn { // Copy the filename in. There is no leading " but there is a trailing " // BUF1: '\??\C:\Users\dave\project\node_modules\my-cli\src\app.js"#node #####!!!!!!!!!!' - // ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^ ^ read_ptr + // ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^ ^ read_ptr // BUF2: 'node "C:\Users\dave\project\node_modules\my-cli\src\app.js"!!!!!!!!!!!!!!!!!!!!' - const length_of_filename_u8 = (@intFromPtr(read_ptr) - (2 * "\x00".len)) - @intFromPtr(buf1_u8); + const length_of_filename_u8 = @intFromPtr(read_ptr) - @intFromPtr(buf1_u8) - nt_object_prefix.len - 6; @memcpy( buf2_u8[shebang_arg_len_u8 + 2 * "\"".len ..][0..length_of_filename_u8], buf1_u8[2 * nt_object_prefix.len ..][0..length_of_filename_u8], @@ -623,10 +623,10 @@ fn launcher(bun_ctx: anytype) noreturn { // | |filename_len where the user args go // | the quote // shebang_arg_len - read_ptr = @ptrFromInt(@intFromPtr(buf2_u8) + shebang_arg_len_u8 + length_of_filename_u8 + 2 * "\"".len); + read_ptr = @ptrFromInt(@intFromPtr(buf2_u8) + length_of_filename_u8 + 2 * "\"\"".len + 2 * nt_object_prefix.len); if (user_arguments_u8.len > 0) { @memcpy(@as([*]u8, @ptrCast(read_ptr)), user_arguments_u8); - read_ptr += user_arguments_u8.len; + read_ptr = @ptrFromInt(@intFromPtr(read_ptr) + user_arguments_u8.len); } // BUF2: 'node "C:\Users\dave\project\node_modules\my-cli\src\app.js" --flags#!!!!!!!!!!' diff --git a/src/string_immutable.zig b/src/string_immutable.zig index abf716e0f7..8ec698fc1e 100644 --- a/src/string_immutable.zig +++ b/src/string_immutable.zig @@ -5948,3 +5948,10 @@ pub inline fn indexOfScalar(input: anytype, scalar: std.meta.Child(@TypeOf(input pub fn containsScalar(input: anytype, item: std.meta.Child(@TypeOf(input))) bool { return indexOfScalar(input, item) != null; } + +pub fn withoutSuffixComptime(input: []const u8, comptime suffix: []const u8) []const u8 { + if (hasSuffixComptime(input, suffix)) { + return input[0 .. input.len - suffix.len]; + } + return input; +}