Skip to content

Commit

Permalink
fix(window): some more bin things (oven-sh#8612)
Browse files Browse the repository at this point in the history
* allow linking bins that do not exist.

* fix some things
  • Loading branch information
paperdave authored and Hanaasagi committed Feb 3, 2024
1 parent dc95b99 commit 1158c58
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 63 deletions.
126 changes: 69 additions & 57 deletions src/cli.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1168,26 +1168,28 @@ 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 {
var args_iter = ArgsIterator{ .buf = bun.argv() };

const argv0 = args_iter.next() orelse return .HelpCommand;

const without_exe = if (Environment.isWindows)
strings.withoutSuffixComptime(argv0, ".exe")
else
argv0;

// symlink is argv[0]
if (isBunX(argv0)) return .BunxCommand;
if (isBunX(without_exe)) return .BunxCommand;

if (isNode(argv0)) {
if (isNode(without_exe)) {
@import("./deps/zig-clap/clap/streaming.zig").warn_on_unrecognized_flag = false;
pretend_to_be_node = true;
return .RunAsNodeCommand;
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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 {};
Expand Down
9 changes: 7 additions & 2 deletions src/cli/run_command.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
Binary file modified src/install/windows-shim/bun_shim_impl.exe
Binary file not shown.
8 changes: 4 additions & 4 deletions src/install/windows-shim/bun_shim_impl.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand All @@ -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#!!!!!!!!!!'
Expand Down
7 changes: 7 additions & 0 deletions src/string_immutable.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

0 comments on commit 1158c58

Please sign in to comment.