Skip to content

Commit

Permalink
escape windows in bun upgrade (#12985)
Browse files Browse the repository at this point in the history
  • Loading branch information
paperdave authored Aug 1, 2024
1 parent dc620ea commit e585f90
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 38 deletions.
2 changes: 1 addition & 1 deletion src/bun.js/WebKit
6 changes: 3 additions & 3 deletions src/cli/upgrade_command.zig
Original file line number Diff line number Diff line change
Expand Up @@ -652,10 +652,10 @@ pub const UpgradeCommand = struct {
// Run a powershell script to unzip the file
const unzip_script = try std.fmt.allocPrint(
ctx.allocator,
"$global:ProgressPreference='SilentlyContinue';Expand-Archive -Path {s} {s} -Force",
"$global:ProgressPreference='SilentlyContinue';Expand-Archive -Path \"{}\" \"{}\" -Force",
.{
tmpname,
tmpdir_path,
bun.fmt.escapePowershell(tmpname),
bun.fmt.escapePowershell(tmpdir_path),
},
);

Expand Down
95 changes: 66 additions & 29 deletions src/fmt.zig
Original file line number Diff line number Diff line change
Expand Up @@ -881,35 +881,6 @@ pub const QuickAndDirtyJavaScriptSyntaxHighlighter = struct {
}
}
}

/// Function for testing in highlighter.test.ts
pub fn jsFunctionSyntaxHighlight(globalThis: *bun.JSC.JSGlobalObject, callframe: *bun.JSC.CallFrame) callconv(bun.JSC.conv) bun.JSC.JSValue {
const args = callframe.arguments(1);
if (args.len < 1) {
globalThis.throwNotEnoughArguments("code", 1, 0);
}

const code = args.ptr[0].toSliceOrNull(globalThis) orelse return .zero;
defer code.deinit();
var buffer = bun.MutableString.initEmpty(bun.default_allocator);
defer buffer.deinit();
var writer = buffer.bufferedWriter();
var formatter = bun.fmt.fmtJavaScript(code.slice(), true);
formatter.limited = false;
std.fmt.format(writer.writer(), "{}", .{formatter}) catch |err| {
globalThis.throwError(err, "Error formatting code");
return .zero;
};

writer.flush() catch |err| {
globalThis.throwError(err, "Error formatting code");
return .zero;
};

var str = bun.String.createUTF8(buffer.list.items);
defer str.deref();
return str.toJS(globalThis);
}
};

pub fn quote(self: string) bun.fmt.QuotedFormatter {
Expand Down Expand Up @@ -1260,3 +1231,69 @@ pub fn NullableFallback(comptime T: type) type {
}
};
}

pub fn escapePowershell(str: []const u8) std.fmt.Formatter(escapePowershellImpl) {
return .{ .data = str };
}

fn escapePowershellImpl(str: []const u8, comptime f: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
comptime bun.assert(f.len == 0);
var remain = str;
while (bun.strings.indexOfAny(remain, "\"`")) |i| {
try writer.writeAll(remain[0..i]);
try writer.writeAll("`");
try writer.writeByte(remain[i]);
remain = remain[i + 1 ..];
}
try writer.writeAll(remain);
}

pub const fmt_js_test_bindings = struct {
const Formatter = enum {
fmtJavaScript,
escapePowershell,
};

/// Internal function for testing in highlighter.test.ts
pub fn jsFunctionStringFormatter(globalThis: *bun.JSC.JSGlobalObject, callframe: *bun.JSC.CallFrame) callconv(bun.JSC.conv) bun.JSC.JSValue {
const args = callframe.arguments(2);
if (args.len < 2) {
globalThis.throwNotEnoughArguments("code", 1, 0);
}

const code = args.ptr[0].toSliceOrNull(globalThis) orelse
return .zero;
defer code.deinit();

var buffer = bun.MutableString.initEmpty(bun.default_allocator);
defer buffer.deinit();
var writer = buffer.bufferedWriter();

const formatter_id: Formatter = @enumFromInt(args.ptr[1].toInt32());
switch (formatter_id) {
.fmtJavaScript => {
var formatter = bun.fmt.fmtJavaScript(code.slice(), true);
formatter.limited = false;
std.fmt.format(writer.writer(), "{}", .{formatter}) catch |err| {
globalThis.throwError(err, "Error formatting");
return .zero;
};
},
.escapePowershell => {
std.fmt.format(writer.writer(), "{}", .{escapePowershell(code.slice())}) catch |err| {
globalThis.throwError(err, "Error formatting");
return .zero;
};
},
}

writer.flush() catch |err| {
globalThis.throwError(err, "Error formatting");
return .zero;
};

var str = bun.String.createUTF8(buffer.list.items);
defer str.deref();
return str.toJS(globalThis);
}
};
16 changes: 11 additions & 5 deletions src/js/internal-for-testing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@

/// <reference path="./private.d.ts" />

export const quickAndDirtyJavaScriptSyntaxHighlighter = $newZigFunction(
const fmtBinding = $newZigFunction(
"fmt.zig",
"QuickAndDirtyJavaScriptSyntaxHighlighter.jsFunctionSyntaxHighlight",
"fmt_js_test_bindings.jsFunctionStringFormatter",
2,
) as (code: string) => string;
) as (code: string, id: number) => string;

export const quickAndDirtyJavaScriptSyntaxHighlighter = (code: string) => fmtBinding(code, 0);
export const escapePowershell = (code: string) => fmtBinding(code, 1);

export const TLSBinding = $cpp("NodeTLS.cpp", "createNodeTLSBinding");

Expand All @@ -23,9 +26,12 @@ export const patchInternals = {
makeDiff: $newZigFunction("patch.zig", "TestingAPIs.makeDiff", 2),
};

const shellLex = $newZigFunction("shell.zig", "TestingAPIs.shellLex", 2);
const shellParse = $newZigFunction("shell.zig", "TestingAPIs.shellParse", 2);

export const shellInternals = {
lex: (a, ...b) => $newZigFunction("shell.zig", "TestingAPIs.shellLex", 2)(a.raw, b),
parse: (a, ...b) => $newZigFunction("shell.zig", "TestingAPIs.shellParse", 2)(a.raw, b),
lex: (a, ...b) => shellLex(a.raw, b) ,
parse: (a, ...b) => shellParse(a.raw, b),
/**
* Checks if the given builtin is disabled on the current platform
*
Expand Down
7 changes: 7 additions & 0 deletions test/internal/highlighter.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { test, expect } from "bun:test";
import { quickAndDirtyJavaScriptSyntaxHighlighter as highlighter } from "bun:internal-for-testing";

test("highlighter", () => {
expect(highlighter("`can do ${123} ${'123'} ${`123`}`").length).toBeLessThan(150);
expect(highlighter("`can do ${123} ${'123'} ${`123`}`123").length).toBeLessThan(150);
});
11 changes: 11 additions & 0 deletions test/internal/powershell-escape.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

import { escapePowershell } from "bun:internal-for-testing";

it("powershell escaping rules", () => {
// This formatter does not include quotes around the string intentionally
expect(escapePowershell("foo")).toBe("foo");
expect(escapePowershell("foo bar")).toBe("foo bar");
expect(escapePowershell("foo\" bar")).toBe("foo`\" bar");
expect(escapePowershell("foo\" `bar")).toBe("foo`\" ``bar");
expect(escapePowershell("foo\" ``\"bar")).toBe("foo`\" `````\"bar");
});
File renamed without changes.

0 comments on commit e585f90

Please sign in to comment.