[bun install] Implement bunfig.toml config

This commit is contained in:
Jarred Sumner
2022-02-11 19:01:00 -08:00
parent bfd7f3398c
commit d67c95d8eb
12 changed files with 977 additions and 86 deletions

BIN
bun.lockb

Binary file not shown.

Binary file not shown.

Binary file not shown.

48
src/api/schema.d.ts generated vendored
View File

@@ -603,6 +603,37 @@ export interface WebsocketMessageResolveID {
id: uint32;
}
export interface NPMRegistry {
url: string;
username: string;
password: string;
token: string;
}
export interface NPMRegistryMap {
scopes: string[];
registries: NPMRegistry[];
}
export interface BunInstall {
default_registry?: NPMRegistry;
scoped?: NPMRegistryMap;
lockfile_path?: string;
save_lockfile_path?: string;
cache_directory?: string;
dry_run?: boolean;
force?: boolean;
save_dev?: boolean;
save_optional?: boolean;
save_peer?: boolean;
save_lockfile?: boolean;
production?: boolean;
save_yarn_lockfile?: boolean;
native_bin_links?: string[];
disable_cache?: boolean;
disable_manifest_cache?: boolean;
}
export declare function encodeStackFrame(
message: StackFrame,
bb: ByteBuffer
@@ -869,3 +900,20 @@ export declare function encodeWebsocketMessageResolveID(
export declare function decodeWebsocketMessageResolveID(
buffer: ByteBuffer
): WebsocketMessageResolveID;
export declare function encodeNPMRegistry(
message: NPMRegistry,
bb: ByteBuffer
): void;
export declare function decodeNPMRegistry(buffer: ByteBuffer): NPMRegistry;
export declare function encodeNPMRegistryMap(
message: NPMRegistryMap,
bb: ByteBuffer
): void;
export declare function decodeNPMRegistryMap(
buffer: ByteBuffer
): NPMRegistryMap;
export declare function encodeBunInstall(
message: BunInstall,
bb: ByteBuffer
): void;
export declare function decodeBunInstall(buffer: ByteBuffer): BunInstall;

271
src/api/schema.js generated
View File

@@ -2748,6 +2748,271 @@ function encodeWebsocketMessageResolveID(message, bb) {
}
}
function decodeNPMRegistry(bb) {
var result = {};
result["url"] = bb.readString();
result["username"] = bb.readString();
result["password"] = bb.readString();
result["token"] = bb.readString();
return result;
}
function encodeNPMRegistry(message, bb) {
var value = message["url"];
if (value != null) {
bb.writeString(value);
} else {
throw new Error('Missing required field "url"');
}
var value = message["username"];
if (value != null) {
bb.writeString(value);
} else {
throw new Error('Missing required field "username"');
}
var value = message["password"];
if (value != null) {
bb.writeString(value);
} else {
throw new Error('Missing required field "password"');
}
var value = message["token"];
if (value != null) {
bb.writeString(value);
} else {
throw new Error('Missing required field "token"');
}
}
function decodeNPMRegistryMap(bb) {
var result = {};
var length = bb.readVarUint();
var values = (result["scopes"] = Array(length));
for (var i = 0; i < length; i++) values[i] = bb.readString();
var length = bb.readVarUint();
var values = (result["registries"] = Array(length));
for (var i = 0; i < length; i++) values[i] = decodeNPMRegistry(bb);
return result;
}
function encodeNPMRegistryMap(message, bb) {
var value = message["scopes"];
if (value != null) {
var values = value,
n = values.length;
bb.writeVarUint(n);
for (var i = 0; i < n; i++) {
value = values[i];
bb.writeString(value);
}
} else {
throw new Error('Missing required field "scopes"');
}
var value = message["registries"];
if (value != null) {
var values = value,
n = values.length;
bb.writeVarUint(n);
for (var i = 0; i < n; i++) {
value = values[i];
encodeNPMRegistry(value, bb);
}
} else {
throw new Error('Missing required field "registries"');
}
}
function decodeBunInstall(bb) {
var result = {};
while (true) {
switch (bb.readByte()) {
case 0:
return result;
case 1:
result["default_registry"] = decodeNPMRegistry(bb);
break;
case 2:
result["scoped"] = decodeNPMRegistryMap(bb);
break;
case 3:
result["lockfile_path"] = bb.readString();
break;
case 4:
result["save_lockfile_path"] = bb.readString();
break;
case 5:
result["cache_directory"] = bb.readString();
break;
case 6:
result["dry_run"] = !!bb.readByte();
break;
case 7:
result["force"] = !!bb.readByte();
break;
case 8:
result["save_dev"] = !!bb.readByte();
break;
case 9:
result["save_optional"] = !!bb.readByte();
break;
case 10:
result["save_peer"] = !!bb.readByte();
break;
case 11:
result["save_lockfile"] = !!bb.readByte();
break;
case 12:
result["production"] = !!bb.readByte();
break;
case 13:
result["save_yarn_lockfile"] = !!bb.readByte();
break;
case 14:
var length = bb.readVarUint();
var values = (result["native_bin_links"] = Array(length));
for (var i = 0; i < length; i++) values[i] = bb.readString();
break;
case 15:
result["disable_cache"] = !!bb.readByte();
break;
case 16:
result["disable_manifest_cache"] = !!bb.readByte();
break;
default:
throw new Error("Attempted to parse invalid message");
}
}
}
function encodeBunInstall(message, bb) {
var value = message["default_registry"];
if (value != null) {
bb.writeByte(1);
encodeNPMRegistry(value, bb);
}
var value = message["scoped"];
if (value != null) {
bb.writeByte(2);
encodeNPMRegistryMap(value, bb);
}
var value = message["lockfile_path"];
if (value != null) {
bb.writeByte(3);
bb.writeString(value);
}
var value = message["save_lockfile_path"];
if (value != null) {
bb.writeByte(4);
bb.writeString(value);
}
var value = message["cache_directory"];
if (value != null) {
bb.writeByte(5);
bb.writeString(value);
}
var value = message["dry_run"];
if (value != null) {
bb.writeByte(6);
bb.writeByte(value);
}
var value = message["force"];
if (value != null) {
bb.writeByte(7);
bb.writeByte(value);
}
var value = message["save_dev"];
if (value != null) {
bb.writeByte(8);
bb.writeByte(value);
}
var value = message["save_optional"];
if (value != null) {
bb.writeByte(9);
bb.writeByte(value);
}
var value = message["save_peer"];
if (value != null) {
bb.writeByte(10);
bb.writeByte(value);
}
var value = message["save_lockfile"];
if (value != null) {
bb.writeByte(11);
bb.writeByte(value);
}
var value = message["production"];
if (value != null) {
bb.writeByte(12);
bb.writeByte(value);
}
var value = message["save_yarn_lockfile"];
if (value != null) {
bb.writeByte(13);
bb.writeByte(value);
}
var value = message["native_bin_links"];
if (value != null) {
bb.writeByte(14);
var values = value,
n = values.length;
bb.writeVarUint(n);
for (var i = 0; i < n; i++) {
value = values[i];
bb.writeString(value);
}
}
var value = message["disable_cache"];
if (value != null) {
bb.writeByte(15);
bb.writeByte(value);
}
var value = message["disable_manifest_cache"];
if (value != null) {
bb.writeByte(16);
bb.writeByte(value);
}
bb.writeByte(0);
}
export { Loader };
export { LoaderKeys };
export { FrameworkEntryPointType };
@@ -2874,3 +3139,9 @@ export { decodeWebsocketCommandBuildWithFilePath };
export { encodeWebsocketCommandBuildWithFilePath };
export { decodeWebsocketMessageResolveID };
export { encodeWebsocketMessageResolveID };
export { decodeNPMRegistry };
export { encodeNPMRegistry };
export { decodeNPMRegistryMap };
export { encodeNPMRegistryMap };
export { decodeBunInstall };
export { encodeBunInstall };

View File

@@ -344,7 +344,6 @@ message TransformOptions {
uint16 port = 25;
MessageLevel logLevel = 26;
}
struct FileHandle {
@@ -516,4 +515,36 @@ struct WebsocketCommandBuildWithFilePath {
struct WebsocketMessageResolveID {
uint32 id;
}
struct NPMRegistry {
string url;
string username;
string password;
string token;
}
struct NPMRegistryMap {
string[] scopes;
NPMRegistry[] registries;
}
message BunInstall {
NPMRegistry default_registry = 1;
NPMRegistryMap scoped = 2;
string lockfile_path = 3;
string save_lockfile_path = 4;
string cache_directory = 5;
bool dry_run = 6;
bool force = 7;
bool save_dev = 8;
bool save_optional = 9;
bool save_peer = 10;
bool save_lockfile = 11;
bool production = 12;
bool save_yarn_lockfile = 13;
string[] native_bin_links = 14;
bool disable_cache = 15;
bool disable_manifest_cache = 16;
}

View File

@@ -2617,4 +2617,239 @@ pub const Api = struct {
try writer.writeInt(this.id);
}
};
pub const NpmRegistry = struct {
/// url
url: []const u8,
/// username
username: []const u8,
/// password
password: []const u8,
/// token
token: []const u8,
pub fn decode(reader: anytype) anyerror!NpmRegistry {
var this = std.mem.zeroes(NpmRegistry);
this.url = try reader.readValue([]const u8);
this.username = try reader.readValue([]const u8);
this.password = try reader.readValue([]const u8);
this.token = try reader.readValue([]const u8);
return this;
}
pub fn encode(this: *const @This(), writer: anytype) anyerror!void {
try writer.writeValue(@TypeOf(this.url), this.url);
try writer.writeValue(@TypeOf(this.username), this.username);
try writer.writeValue(@TypeOf(this.password), this.password);
try writer.writeValue(@TypeOf(this.token), this.token);
}
};
pub const NpmRegistryMap = struct {
/// scopes
scopes: []const []const u8,
/// registries
registries: []const NpmRegistry,
pub fn decode(reader: anytype) anyerror!NpmRegistryMap {
var this = std.mem.zeroes(NpmRegistryMap);
this.scopes = try reader.readArray([]const u8);
this.registries = try reader.readArray(NpmRegistry);
return this;
}
pub fn encode(this: *const @This(), writer: anytype) anyerror!void {
try writer.writeArray([]const u8, this.scopes);
try writer.writeArray(NpmRegistry, this.registries);
}
};
pub const BunInstall = struct {
/// default_registry
default_registry: ?NpmRegistry = null,
/// scoped
scoped: ?NpmRegistryMap = null,
/// lockfile_path
lockfile_path: ?[]const u8 = null,
/// save_lockfile_path
save_lockfile_path: ?[]const u8 = null,
/// cache_directory
cache_directory: ?[]const u8 = null,
/// dry_run
dry_run: ?bool = null,
/// force
force: ?bool = null,
/// save_dev
save_dev: ?bool = null,
/// save_optional
save_optional: ?bool = null,
/// save_peer
save_peer: ?bool = null,
/// save_lockfile
save_lockfile: ?bool = null,
/// production
production: ?bool = null,
/// save_yarn_lockfile
save_yarn_lockfile: ?bool = null,
/// native_bin_links
native_bin_links: []const []const u8,
/// disable_cache
disable_cache: ?bool = null,
/// disable_manifest_cache
disable_manifest_cache: ?bool = null,
pub fn decode(reader: anytype) anyerror!BunInstall {
var this = std.mem.zeroes(BunInstall);
while (true) {
switch (try reader.readByte()) {
0 => {
return this;
},
1 => {
this.default_registry = try reader.readValue(NpmRegistry);
},
2 => {
this.scoped = try reader.readValue(NpmRegistryMap);
},
3 => {
this.lockfile_path = try reader.readValue([]const u8);
},
4 => {
this.save_lockfile_path = try reader.readValue([]const u8);
},
5 => {
this.cache_directory = try reader.readValue([]const u8);
},
6 => {
this.dry_run = try reader.readValue(bool);
},
7 => {
this.force = try reader.readValue(bool);
},
8 => {
this.save_dev = try reader.readValue(bool);
},
9 => {
this.save_optional = try reader.readValue(bool);
},
10 => {
this.save_peer = try reader.readValue(bool);
},
11 => {
this.save_lockfile = try reader.readValue(bool);
},
12 => {
this.production = try reader.readValue(bool);
},
13 => {
this.save_yarn_lockfile = try reader.readValue(bool);
},
14 => {
this.native_bin_links = try reader.readArray([]const u8);
},
15 => {
this.disable_cache = try reader.readValue(bool);
},
16 => {
this.disable_manifest_cache = try reader.readValue(bool);
},
else => {
return error.InvalidMessage;
},
}
}
unreachable;
}
pub fn encode(this: *const @This(), writer: anytype) anyerror!void {
if (this.default_registry) |default_registry| {
try writer.writeFieldID(1);
try writer.writeValue(@TypeOf(default_registry), default_registry);
}
if (this.scoped) |scoped| {
try writer.writeFieldID(2);
try writer.writeValue(@TypeOf(scoped), scoped);
}
if (this.lockfile_path) |lockfile_path| {
try writer.writeFieldID(3);
try writer.writeValue(@TypeOf(lockfile_path), lockfile_path);
}
if (this.save_lockfile_path) |save_lockfile_path| {
try writer.writeFieldID(4);
try writer.writeValue(@TypeOf(save_lockfile_path), save_lockfile_path);
}
if (this.cache_directory) |cache_directory| {
try writer.writeFieldID(5);
try writer.writeValue(@TypeOf(cache_directory), cache_directory);
}
if (this.dry_run) |dry_run| {
try writer.writeFieldID(6);
try writer.writeInt(@as(u8, @boolToInt(dry_run)));
}
if (this.force) |force| {
try writer.writeFieldID(7);
try writer.writeInt(@as(u8, @boolToInt(force)));
}
if (this.save_dev) |save_dev| {
try writer.writeFieldID(8);
try writer.writeInt(@as(u8, @boolToInt(save_dev)));
}
if (this.save_optional) |save_optional| {
try writer.writeFieldID(9);
try writer.writeInt(@as(u8, @boolToInt(save_optional)));
}
if (this.save_peer) |save_peer| {
try writer.writeFieldID(10);
try writer.writeInt(@as(u8, @boolToInt(save_peer)));
}
if (this.save_lockfile) |save_lockfile| {
try writer.writeFieldID(11);
try writer.writeInt(@as(u8, @boolToInt(save_lockfile)));
}
if (this.production) |production| {
try writer.writeFieldID(12);
try writer.writeInt(@as(u8, @boolToInt(production)));
}
if (this.save_yarn_lockfile) |save_yarn_lockfile| {
try writer.writeFieldID(13);
try writer.writeInt(@as(u8, @boolToInt(save_yarn_lockfile)));
}
if (this.native_bin_links) |native_bin_links| {
try writer.writeFieldID(14);
try writer.writeArray([]const u8, native_bin_links);
}
if (this.disable_cache) |disable_cache| {
try writer.writeFieldID(15);
try writer.writeInt(@as(u8, @boolToInt(disable_cache)));
}
if (this.disable_manifest_cache) |disable_manifest_cache| {
try writer.writeFieldID(16);
try writer.writeInt(@as(u8, @boolToInt(disable_manifest_cache)));
}
try writer.endMessage();
}
};
};

View File

@@ -12,7 +12,6 @@ const URL = @import("./query_string_map.zig").URL;
const C = _global.C;
const options = @import("./options.zig");
const logger = @import("./logger.zig");
const cache = @import("./cache.zig");
const js_ast = @import("./js_ast.zig");
const js_lexer = @import("./js_lexer.zig");
const Defines = @import("./defines.zig");
@@ -45,6 +44,68 @@ pub const Bunfig = struct {
return error.@"Invalid Bunfig";
}
fn parseRegistry(this: *Parser, expr: js_ast.Expr) !Api.NpmRegistry {
var registry = std.mem.zeroes(Api.NpmRegistry);
switch (expr.data) {
.e_string => |str| {
const url = URL.parse(str.utf8);
// Token
if (url.username.len == 0 and url.password.len > 0) {
registry.token = url.password;
registry.url = try std.fmt.allocPrint(this.allocator, "{s}://{s}/{s}", .{ url.displayProtocol(), url.displayHostname(), std.mem.trimLeft(u8, url.pathname, "/") });
} else if (url.username.len > 0 and url.password.len > 0) {
registry.username = url.username;
registry.password = url.password;
registry.url = try std.fmt.allocPrint(this.allocator, "{s}://{s}/{s}", .{ url.displayProtocol(), url.displayHostname(), std.mem.trimLeft(u8, url.pathname, "/") });
} else {
registry.url = url.href;
}
},
.e_object => |obj| {
if (obj.get("url")) |url| {
try this.expect(url, .e_string);
registry.url = url.data.e_string.utf8;
}
if (obj.get("username")) |username| {
try this.expect(username, .e_string);
registry.username = username.data.e_string.utf8;
}
if (obj.get("password")) |password| {
try this.expect(password, .e_string);
registry.password = password.data.e_string.utf8;
}
if (obj.get("token")) |token| {
try this.expect(token, .e_string);
registry.token = token.data.e_string.utf8;
}
},
else => {
try this.addError(expr.loc, "Expected registry to be a URL string or an object");
},
}
return registry;
}
fn loadLogLevel(this: *Parser, expr: js_ast.Expr) !void {
try this.expect(expr, .e_string);
const Matcher = strings.ExactSizeMatcher(8);
this.bunfig.log_level = switch (Matcher.match(expr.asString(this.allocator).?)) {
Matcher.case("debug") => Api.MessageLevel.debug,
Matcher.case("error") => Api.MessageLevel.err,
Matcher.case("warn") => Api.MessageLevel.warn,
else => {
try this.addError(expr.loc, "Invalid log level, must be one of debug, error, or warn");
unreachable;
},
};
}
pub fn parse(this: *Parser, comptime cmd: Command.Tag) !void {
const json = this.json;
var allocator = this.allocator;
@@ -53,6 +114,10 @@ pub const Bunfig = struct {
try this.addError(json.loc, "bunfig expects an object { } at the root");
}
if (json.get("logLevel")) |expr| {
try this.loadLogLevel(expr);
}
if (json.get("define")) |expr| {
try this.expect(expr, .e_object);
var valid_count: usize = 0;
@@ -89,6 +154,10 @@ pub const Bunfig = struct {
this.ctx.debug.fallback_only = disable.asBool() orelse false;
}
if (expr.get("logLevel")) |expr2| {
try this.loadLogLevel(expr2);
}
if (expr.get("port")) |port| {
try this.expect(port, .e_number);
this.bunfig.port = port.data.e_number.toU16();
@@ -99,6 +168,169 @@ pub const Bunfig = struct {
}
}
if (comptime cmd.isNPMRelated()) {
if (json.get("install")) |bun| {
var install: *Api.BunInstall = this.ctx.install orelse brk: {
var install_ = try this.allocator.create(Api.BunInstall);
install_.* = std.mem.zeroes(Api.BunInstall);
this.ctx.install = install_;
break :brk install_;
};
if (bun.get("registry")) |registry| {
install.default_registry = try this.parseRegistry(registry);
}
if (bun.get("scopes")) |scopes| {
var registry_map = install.scoped orelse std.mem.zeroes(Api.NpmRegistryMap);
try this.expect(scopes, .e_object);
const count = scopes.data.e_object.properties.len + registry_map.registries.len;
var registries = std.ArrayListUnmanaged(Api.NpmRegistry){
.items = try this.allocator.alloc(Api.NpmRegistry, count),
.capacity = count,
};
registries.appendSliceAssumeCapacity(registry_map.registries);
var names = std.ArrayListUnmanaged(string){
.items = try this.allocator.alloc(string, count),
.capacity = count,
};
names.appendSliceAssumeCapacity(registry_map.names);
for (scopes.data.e_object.properties.slice()) |prop| {
const name_ = prop.key.?.data.e_string.string(this.allocator) orelse continue;
const value = prop.value orelse continue;
if (name_.len == 0) continue;
const name = if (name_[0] == '@') name_[1..] else name_;
var index = names.items.len;
for (names.items) |comparator, i| {
if (strings.eql(name, comparator)) {
index = i;
break;
}
}
if (index == names.items.len) {
names.items.len += 1;
registries.items.len += 1;
}
names.items[index] = name;
registries.items[index] = try this.parseRegistry(value);
}
registry_map.registries = registries.items;
registry_map.names = names.items;
install.scoped = registry_map;
}
if (bun.get("dryRun")) |dry_run| {
if (dry_run.asBool()) |value| {
install.dry_run = value;
}
}
if (bun.get("production")) |production| {
if (production.asBool()) |value| {
install.production = value;
}
}
if (bun.get("lockfile")) |lockfile_expr| {
if (lockfile_expr.get("outputFormat")) |lockfile| {
try this.expect(lockfile, .e_string);
if (lockfile.asString(this.allocator)) |value| {
if (!(strings.eqlComptime(value, "bun"))) {
if (!strings.eqlComptime(value, "yarn")) {
try this.addError(lockfile.loc, "Invalid lockfile format, only 'yarn' output is implemented");
}
install.save_yarn_lockfile = true;
}
}
}
if (lockfile_expr.get("save")) |lockfile| {
if (lockfile.asString()) |value| {
install.save_lockfile = value;
}
}
if (lockfile_expr.get("path")) |lockfile| {
if (lockfile.asString()) |value| {
install.lockfile_path = value;
}
}
if (lockfile_expr.get("savePath")) |lockfile| {
if (lockfile.asString()) |value| {
install.save_lockfile_path = value;
}
}
}
if (bun.get("optional")) |optional| {
if (optional.asBool()) |value| {
install.save_optional = value;
}
}
if (bun.get("peer")) |optional| {
if (optional.asBool()) |value| {
install.save_peer = value;
}
}
if (bun.get("dev")) |optional| {
if (optional.asBool()) |value| {
install.save_dev = value;
}
}
if (bun.get("logLevel")) |expr| {
try this.loadLogLevel(expr);
}
if (bun.get("cache")) |cache| {
load: {
if (cache.asBool()) |value| {
if (!value) {
install.disable_cache = true;
install.disable_manifest_cache = true;
}
break :load;
}
if (cache.asString(allocator)) |value| {
install.cache_directory = value;
break :load;
}
if (cache.data == .e_object) {
if (cache.get("disable")) |disable| {
if (disable.asBool()) |value| {
install.disable_cache = value;
}
}
if (cache.get("disableManifest")) |disable| {
if (disable.asBool()) |value| {
install.disable_manifest_cache = value;
}
}
if (cache.get("directory")) |directory| {
if (directory.asString(allocator)) |value| {
install.cache_directory = value;
}
}
}
}
}
}
}
if (json.get("bundle")) |bun| {
if (comptime cmd == .DevCommand or cmd == .BuildCommand or cmd == .RunCommand or cmd == .AutoCommand or cmd == .BunCommand) {
if (bun.get("saveTo")) |file| {
@@ -108,6 +340,10 @@ pub const Bunfig = struct {
}
if (comptime cmd == .BunCommand) {
if (bun.get("logLevel")) |expr2| {
try this.loadLogLevel(expr2);
}
if (bun.get("entryPoints")) |entryPoints| {
try this.expect(entryPoints, .e_array);
const items = entryPoints.data.e_array.items.slice();
@@ -224,21 +460,6 @@ pub const Bunfig = struct {
};
}
if (json.get("logLevel")) |expr| {
try this.expect(expr, .e_string);
const Matcher = strings.ExactSizeMatcher(8);
this.bunfig.log_level = switch (Matcher.match(expr.asString(allocator).?)) {
Matcher.case("debug") => Api.MessageLevel.debug,
Matcher.case("error") => Api.MessageLevel.err,
Matcher.case("warn") => Api.MessageLevel.warn,
else => {
try this.addError(expr.loc, "Invalid log level, must be one of debug, error, or warn");
unreachable;
},
};
}
Analytics.Features.bunfig = true;
}

View File

@@ -205,6 +205,97 @@ pub const Arguments = struct {
Global.exit(0);
}
fn loadConfigPath(allocator: std.mem.Allocator, auto_loaded: bool, config_path: [:0]const u8, ctx: *Command.Context, comptime cmd: Command.Tag) !void {
var config_file = std.fs.openFileAbsoluteZ(config_path, .{ .read = true }) catch |err| {
if (auto_loaded) return;
Output.prettyErrorln("<r><red>error<r>: {s} opening config \"{s}\"", .{
@errorName(err),
std.mem.span(config_path),
});
Output.flush();
Global.exit(1);
};
defer config_file.close();
var contents = config_file.readToEndAlloc(allocator, std.math.maxInt(usize)) catch |err| {
if (auto_loaded) return;
Output.prettyErrorln("<r><red>error<r>: {s} reading config \"{s}\"", .{
@errorName(err),
std.mem.span(config_path),
});
Output.flush();
Global.exit(1);
};
js_ast.Stmt.Data.Store.create(allocator);
js_ast.Expr.Data.Store.create(allocator);
defer {
js_ast.Stmt.Data.Store.reset();
js_ast.Expr.Data.Store.reset();
}
var original_level = ctx.log.level;
defer {
ctx.log.level = original_level;
}
ctx.log.level = logger.Log.Level.warn;
try Bunfig.parse(allocator, logger.Source.initPathString(std.mem.span(config_path), contents), ctx, cmd);
}
fn getHomeConfigPath(cwd: string, buf: *[std.fs.MAX_PATH_BYTES]u8) ?[:0]const u8 {
if (std.os.getenvZ("XDG_CONFIG_HOME")) |data_dir| {
var paths = [_]string{ data_dir, ".bunfig.toml" };
return resolve_path.joinAbsStringBufZ(cwd, buf, &paths, .auto);
}
if (std.os.getenvZ("HOME")) |data_dir| {
var paths = [_]string{ data_dir, ".bunfig.toml" };
return resolve_path.joinAbsStringBufZ(cwd, buf, &paths, .auto);
}
return null;
}
pub fn loadConfig(allocator: std.mem.Allocator, args: clap.Args(clap.Help, &params), ctx: *Command.Context, comptime cmd: Command.Tag) !void {
var config_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
if (comptime cmd.readGlobalConfig()) {
if (getHomeConfigPath(ctx.args.absolute_working_dir, &config_buf)) |path| {
try loadConfigPath(allocator, true, path, ctx, comptime cmd);
}
}
var config_path_: []const u8 = "";
if (args.option("--config")) |config_path__| {
config_path_ = config_path__;
}
var auto_loaded: bool = false;
if (config_path_.len == 0 and (args.option("--config") != null or Command.Tag.always_loads_config.get(cmd))) {
config_path_ = "bunfig.toml";
auto_loaded = true;
}
if (config_path_.len == 0) {
return;
}
var config_path: [:0]u8 = undefined;
if (config_path_[0] == '/') {
@memcpy(&config_buf, config_path_.ptr, config_path_.len);
config_buf[config_path_.len] = 0;
config_path = config_buf[0..config_path_.len :0];
} else {
var parts = [_]string{ ctx.args.absolute_working_dir.?, config_path_ };
config_path_ = resolve_path.joinAbsStringBuf(
ctx.args.absolute_working_dir.?,
&config_buf,
&parts,
.auto,
);
config_buf[config_path_.len] = 0;
config_path = config_buf[0..config_path_.len :0];
}
try loadConfigPath(allocator, auto_loaded, config_path, ctx, comptime cmd);
}
pub fn parse(allocator: std.mem.Allocator, ctx: *Command.Context, comptime cmd: Command.Tag) !Api.TransformOptions {
var diag = clap.Diagnostic{};
@@ -229,79 +320,14 @@ pub const Arguments = struct {
cwd = try std.process.getCwdAlloc(allocator);
}
var opts: Api.TransformOptions = ctx.args;
opts.absolute_working_dir = cwd;
ctx.args.absolute_working_dir = cwd;
if (comptime Command.Tag.loads_config.get(cmd)) {
load_config: {
var config_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
var config_path_: []const u8 = "";
if (args.option("--config")) |config_path__| {
config_path_ = config_path__;
}
var auto_loaded: bool = false;
if (config_path_.len == 0 and (args.option("--config") != null or Command.Tag.always_loads_config.get(cmd))) {
config_path_ = "bunfig.toml";
auto_loaded = true;
}
if (config_path_.len == 0) {
break :load_config;
}
var config_path: [:0]u8 = undefined;
if (config_path_[0] == '/') {
@memcpy(&config_buf, config_path_.ptr, config_path_.len);
config_buf[config_path_.len] = 0;
config_path = config_buf[0..config_path_.len :0];
} else {
var parts = [_]string{ cwd, config_path_ };
config_path_ = resolve_path.joinAbsStringBuf(
cwd,
&config_buf,
&parts,
.auto,
);
config_buf[config_path_.len] = 0;
config_path = config_buf[0..config_path_.len :0];
}
var config_file = std.fs.openFileAbsoluteZ(config_path, .{ .read = true }) catch |err| {
if (auto_loaded) break :load_config;
Output.prettyErrorln("<r><red>error<r>: {s} opening config \"{s}\"", .{
@errorName(err),
std.mem.span(config_path),
});
Output.flush();
Global.exit(1);
};
var contents = config_file.readToEndAlloc(allocator, std.math.maxInt(usize)) catch |err| {
if (auto_loaded) break :load_config;
Output.prettyErrorln("<r><red>error<r>: {s} reading config \"{s}\"", .{
@errorName(err),
std.mem.span(config_path),
});
Output.flush();
Global.exit(1);
};
js_ast.Stmt.Data.Store.create(allocator);
js_ast.Expr.Data.Store.create(allocator);
defer {
js_ast.Stmt.Data.Store.reset();
js_ast.Expr.Data.Store.reset();
}
var original_level = ctx.log.level;
defer {
ctx.log.level = original_level;
}
ctx.log.level = logger.Log.Level.warn;
try Bunfig.parse(allocator, logger.Source.initPathString(std.mem.span(config_path), contents), ctx, cmd);
opts = ctx.args;
}
try loadConfig(allocator, args, ctx, cmd);
}
var opts: Api.TransformOptions = ctx.args;
var defines_tuple = try DefineColonList.resolve(allocator, args.options("--define"));
if (defines_tuple.keys.len > 0) {
@@ -699,6 +725,7 @@ pub const Command = struct {
log: *logger.Log,
allocator: std.mem.Allocator,
positionals: []const string = &[_]string{},
install: ?*Api.BunInstall = null,
debug: DebugOptions = DebugOptions{},
@@ -1126,6 +1153,20 @@ pub const Command = struct {
PackageManagerCommand,
TestCommand,
pub fn readGlobalConfig(this: Tag) bool {
return switch (this) {
.PackageManagerCommand, .InstallCommand, .AddCommand, .RemoveCommand => true,
else => false,
};
}
pub fn isNPMRelated(this: Tag) bool {
return switch (this) {
.PackageManagerCommand, .InstallCommand, .AddCommand, .RemoveCommand => true,
else => false,
};
}
pub const cares_about_bun_file: std.EnumArray(Tag, bool) = std.EnumArray(Tag, bool).initDefault(false, .{
.AutoCommand = true,
.BuildCommand = true,

View File

@@ -396,6 +396,21 @@ pub const Loader = struct {
const empty_string_value: string = "\"\"";
pub fn get(this: *const Loader, key: string) ?string {
var _key = key;
if (_key.len > 0 and _key[0] == '$') {
_key = key[1..];
}
if (_key.len == 0) return null;
return this.map.get(_key);
}
pub fn getAuto(this: *const Loader, key: string) string {
return this.get(key) orelse key;
}
/// Load values from the environment into Define.
///
/// If there is a framework, values from the framework are inserted with a

View File

@@ -36,6 +36,24 @@ pub fn append(this: *HeaderBuilder, name: string, value: string) void {
this.entries.appendAssumeCapacity(Headers.Kv{ .name = name_ptr, .value = value_ptr });
}
pub fn appendFmt(this: *HeaderBuilder, name: string, comptime fmt: string, args: anytype) void {
const name_ptr = Api.StringPointer{
.offset = @truncate(u32, this.content.len),
.length = @truncate(u32, name.len),
};
_ = this.content.append(name);
const value = this.content.fmt(fmt, args);
const value_ptr = Api.StringPointer{
.offset = @truncate(u32, this.content.len),
.length = @truncate(u32, value.len),
};
this.entries.appendAssumeCapacity(Headers.Kv{ .name = name_ptr, .value = value_ptr });
}
pub fn apply(this: *HeaderBuilder, client: *HTTPClient) void {
client.header_entries = this.entries;
client.header_buf = this.content.ptr.?[0..this.content.len];

View File

@@ -30,3 +30,14 @@ pub fn append(this: *StringBuilder, slice: string) string {
assert(this.len <= this.cap);
return result;
}
const std = @import("std");
pub fn fmt(this: *StringBuilder, comptime str: string, args: anytype) string {
assert(this.len <= this.cap); // didn't count everything
assert(this.ptr != null); // must call allocate first
var buf = this.ptr.?[this.len..this.cap];
const out = std.fmt.bufPrint(buf, str, args) catch unreachable;
this.len += out.len;
return out;
}