Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "bin" field to bun.lock #15763

Merged
merged 10 commits into from
Dec 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/bun.js/ConsoleObject.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1879,7 +1879,7 @@ pub const Formatter = struct {

writer.print(
comptime Output.prettyFmt("<r><green>{s}<r><d>:<r> ", enable_ansi_colors),
.{bun.fmt.formatJSONString(key.slice())},
.{bun.fmt.formatJSONStringLatin1(key.slice())},
);
}
} else if (Environment.isDebug and is_private_symbol) {
Expand Down
4 changes: 2 additions & 2 deletions src/bun.js/javascript.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3000,7 +3000,7 @@ pub const VirtualMachine = struct {
"{s} resolving preload {}",
.{
@errorName(e),
bun.fmt.formatJSONString(preload),
bun.fmt.formatJSONStringLatin1(preload),
},
) catch unreachable;
return e;
Expand All @@ -3012,7 +3012,7 @@ pub const VirtualMachine = struct {
this.allocator,
"preload not found {}",
.{
bun.fmt.formatJSONString(preload),
bun.fmt.formatJSONStringLatin1(preload),
},
) catch unreachable;
return error.ModuleNotFound;
Expand Down
2 changes: 1 addition & 1 deletion src/bun.js/test/pretty_format.zig
Original file line number Diff line number Diff line change
Expand Up @@ -861,7 +861,7 @@ pub const JestPrettyFormat = struct {

writer.print(
comptime Output.prettyFmt("<r><green>{s}<r><d>:<r> ", enable_ansi_colors),
.{bun.fmt.formatJSONString(key.slice())},
.{bun.fmt.formatJSONStringLatin1(key.slice())},
);
}
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/cli/init_command.zig
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ pub const InitCommand = struct {
" \"'",
fields.entry_point,
)) {
Output.prettyln(" <r><cyan>bun run {any}<r>", .{bun.fmt.formatJSONString(fields.entry_point)});
Output.prettyln(" <r><cyan>bun run {any}<r>", .{bun.fmt.formatJSONStringLatin1(fields.entry_point)});
} else {
Output.prettyln(" <r><cyan>bun run {s}<r>", .{fields.entry_point});
}
Expand Down
2 changes: 1 addition & 1 deletion src/fmt.zig
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ const JSONFormatterUTF8 = struct {
};

/// Expects latin1
pub fn formatJSONString(text: []const u8) JSONFormatter {
pub fn formatJSONStringLatin1(text: []const u8) JSONFormatter {
return .{ .input = text };
}

Expand Down
97 changes: 85 additions & 12 deletions src/install/bin.zig
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,11 @@ const Lockfile = Install.Lockfile;
/// - map where keys are names of the binaries and values are file paths to the binaries
pub const Bin = extern struct {
tag: Tag = Tag.none,
unset: u8 = 0,
_padding_tag: [2]u8 = .{0} ** 2,
_padding_tag: [3]u8 = .{0} ** 3,

// Largest member must be zero initialized
value: Value = Value{ .map = ExternalStringList{} },

pub fn isUnset(this: *const Bin) bool {
return this.unset != 0;
}

pub fn count(this: *const Bin, buf: []const u8, extern_strings: []const ExternalString, comptime StringBuilder: type, builder: StringBuilder) u32 {
switch (this.tag) {
.file => builder.count(this.value.file.slice(buf)),
Expand All @@ -59,26 +54,67 @@ pub const Bin = extern struct {
return 0;
}

pub fn eql(
l: *const Bin,
r: *const Bin,
l_buf: string,
l_extern_strings: []const ExternalString,
r_buf: string,
r_extern_strings: []const ExternalString,
) bool {
if (l.tag != r.tag) return false;

return switch (l.tag) {
.none => true,
.file => l.value.file.eql(r.value.file, l_buf, r_buf),
.dir => l.value.dir.eql(r.value.dir, l_buf, r_buf),
.named_file => l.value.named_file[0].eql(r.value.named_file[0], l_buf, r_buf) and
l.value.named_file[1].eql(r.value.named_file[1], l_buf, r_buf),
.map => {
const l_list = l.value.map.get(l_extern_strings);
const r_list = r.value.map.get(r_extern_strings);
if (l_list.len != r_list.len) return false;

// assuming these maps are small without duplicate keys
var i: usize = 0;
outer: while (i < l_list.len) : (i += 2) {
var j: usize = 0;
while (j < r_list.len) : (j += 2) {
if (l_list[i].hash == r_list[j].hash) {
if (l_list[i + 1].hash != r_list[j + 1].hash) {
return false;
}

continue :outer;
}
}

// not found
return false;
}

return true;
},
};
}

pub fn clone(this: *const Bin, buf: []const u8, prev_external_strings: []const ExternalString, all_extern_strings: []ExternalString, extern_strings_slice: []ExternalString, comptime StringBuilder: type, builder: StringBuilder) Bin {
switch (this.tag) {
.none => {
return Bin{
.tag = .none,
.unset = this.unset,
.value = Value.init(.{ .none = {} }),
};
},
.file => {
return Bin{
.tag = .file,
.unset = this.unset,
.value = Value.init(.{ .file = builder.append(String, this.value.file.slice(buf)) }),
};
},
.named_file => {
return Bin{
.tag = .named_file,
.unset = this.unset,
.value = Value.init(
.{
.named_file = [2]String{
Expand All @@ -92,7 +128,6 @@ pub const Bin = extern struct {
.dir => {
return Bin{
.tag = .dir,
.unset = this.unset,
.value = Value.init(.{ .dir = builder.append(String, this.value.dir.slice(buf)) }),
};
},
Expand All @@ -103,7 +138,6 @@ pub const Bin = extern struct {

return Bin{
.tag = .map,
.unset = this.unset,
.value = Value.init(.{ .map = ExternalStringList.init(all_extern_strings, extern_strings_slice) }),
};
},
Expand All @@ -118,7 +152,6 @@ pub const Bin = extern struct {

const cloned: Bin = .{
.tag = this.tag,
.unset = this.unset,

.value = switch (this.tag) {
.none => Value.init(.{ .none = {} }),
Expand Down Expand Up @@ -236,6 +269,46 @@ pub const Bin = extern struct {
return .{};
}

/// Writes value of bin to a single line, either as a string or object. Cannot be `.none` because a value is expected to be
/// written to the json, as a property value or array value.
pub fn toSingleLineJson(this: *const Bin, buf: string, extern_strings: []const ExternalString, writer: anytype) @TypeOf(writer).Error!void {
bun.debugAssert(this.tag != .none);
switch (this.tag) {
.none => {},
.file => {
try writer.print("{}", .{this.value.file.fmtJson(buf, .{})});
},
.named_file => {
try writer.writeByte('{');
try writer.print(" {}: {} ", .{
this.value.named_file[0].fmtJson(buf, .{}),
this.value.named_file[1].fmtJson(buf, .{}),
});
try writer.writeByte('}');
},
.dir => {
try writer.print("{}", .{this.value.dir.fmtJson(buf, .{})});
},
.map => {
try writer.writeByte('{');
const list = this.value.map.get(extern_strings);
var first = true;
var i: usize = 0;
while (i < list.len) : (i += 2) {
if (!first) {
try writer.writeByte(',');
}
first = false;
try writer.print(" {}: {}", .{
list[i].value.fmtJson(buf, .{}),
list[i + 1].value.fmtJson(buf, .{}),
});
}
try writer.writeAll(" }");
},
}
}

pub fn init() Bin {
return bun.serializable(.{ .tag = .none, .value = Value.init(.{ .none = {} }) });
}
Expand Down
Loading
Loading