Compare commits

...

8 Commits

Author SHA1 Message Date
Colin McDonnell
406a6b5718 Tweak helptext 2023-08-21 17:49:58 -07:00
Colin McDonnell
4003856575 Add test for absolute paths 2023-08-21 17:49:58 -07:00
Colin McDonnell
2bb084e3f3 Clean up 2023-08-21 17:49:58 -07:00
Colin McDonnell
517643c7da Clean up 2023-08-21 17:49:58 -07:00
Colin McDonnell
e78056ce14 Remove comment 2023-08-21 17:49:58 -07:00
Colin McDonnell
94e5823bbd Fix priority order 2023-08-21 17:49:58 -07:00
Colin McDonnell
8a3f85c81a Add tests 2023-08-21 17:49:58 -07:00
Colin McDonnell
edb6ed62a4 Support bun.json 2023-08-21 17:49:58 -07:00
7 changed files with 283 additions and 45 deletions

View File

@@ -5260,7 +5260,7 @@ pub fn NewServer(comptime NamespaceType: type, comptime ssl_enabled_: bool, comp
editor.open(ctx.path, url, line, column, this.allocator) catch Output.prettyErrorln("Failed to open editor", .{});
} else {
resp.writeStatus("500 Missing Editor :(");
resp.end("Please set your editor in bunfig.toml", false);
resp.end("Please set your editor in bun.json", false);
}
}

View File

@@ -55,7 +55,9 @@ pub const Run = struct {
var arena = try Arena.init();
if (!ctx.debug.loaded_bunfig) {
try bun.CLI.Arguments.loadConfigPath(ctx.allocator, true, "bunfig.toml", &ctx, .RunCommand);
_ = bun.CLI.Arguments.loadConfigPath(ctx.allocator, true, "bun.json", &ctx, .RunCommand) catch blk: {
break :blk bun.CLI.Arguments.loadConfigPath(ctx.allocator, true, "bunfig.toml", &ctx, .RunCommand) catch false;
};
}
run = .{
@@ -142,7 +144,9 @@ pub const Run = struct {
var arena = try Arena.init();
if (!ctx.debug.loaded_bunfig) {
try bun.CLI.Arguments.loadConfigPath(ctx.allocator, true, "bunfig.toml", &ctx, .RunCommand);
_ = bun.CLI.Arguments.loadConfigPath(ctx.allocator, true, "bun.json", &ctx, .RunCommand) catch blk: {
break :blk bun.CLI.Arguments.loadConfigPath(ctx.allocator, true, "bunfig.toml", &ctx, .RunCommand) catch false;
};
}
run = .{

View File

@@ -133,10 +133,10 @@ pub const Arguments = struct {
pub const ParamType = clap.Param(clap.Help);
const shared_public_params = [_]ParamType{
clap.parseParam("-h, --help Display this help and exit.") catch unreachable,
clap.parseParam("-h, --help Display this help and exit") catch unreachable,
clap.parseParam("-b, --bun Force a script or package to use Bun.js instead of Node.js (via symlinking node)") catch unreachable,
clap.parseParam("--cwd <STR> Absolute path to resolve files & entry points from. This just changes the process' cwd.") catch unreachable,
clap.parseParam("-c, --config <PATH>? Config file to load bun from (e.g. -c bunfig.toml") catch unreachable,
clap.parseParam("-c, --config <PATH> Specify path to config file (e.g. -c bun.json)") catch unreachable,
clap.parseParam("--extension-order <STR>... Defaults to: .tsx,.ts,.jsx,.js,.json ") catch unreachable,
clap.parseParam("--jsx-factory <STR> Changes the function called when compiling JSX elements using the classic JSX runtime") catch unreachable,
clap.parseParam("--jsx-fragment <STR> Changes the function called when compiling JSX fragments") catch unreachable,
@@ -240,10 +240,10 @@ pub const Arguments = struct {
Global.exit(0);
}
pub fn loadConfigPath(allocator: std.mem.Allocator, auto_loaded: bool, config_path: [:0]const u8, ctx: *Command.Context, comptime cmd: Command.Tag) !void {
pub fn loadConfigPath(allocator: std.mem.Allocator, auto_loaded: bool, config_path: [:0]const u8, ctx: *Command.Context, comptime cmd: Command.Tag) !bool {
var config_file = std.fs.File{
.handle = std.os.openZ(config_path, std.os.O.RDONLY, 0) catch |err| {
if (auto_loaded) return;
if (auto_loaded) return false;
Output.prettyErrorln("<r><red>error<r>: {s} opening config \"{s}\"", .{
@errorName(err),
config_path,
@@ -253,7 +253,7 @@ pub const Arguments = struct {
};
defer config_file.close();
var contents = config_file.readToEndAlloc(allocator, std.math.maxInt(usize)) catch |err| {
if (auto_loaded) return;
if (auto_loaded) return false;
Output.prettyErrorln("<r><red>error<r>: {s} reading config \"{s}\"", .{
@errorName(err),
config_path,
@@ -273,9 +273,10 @@ pub const Arguments = struct {
}
ctx.log.level = logger.Log.Level.warn;
try Bunfig.parse(allocator, logger.Source.initPathString(bun.asByteSlice(config_path), contents), ctx, cmd);
return true;
}
fn getHomeConfigPath(buf: *[bun.MAX_PATH_BYTES]u8) ?[:0]const u8 {
fn getRootBunfigPath(buf: *[bun.MAX_PATH_BYTES]u8) ?[:0]const u8 {
if (bun.getenvZ("XDG_CONFIG_HOME") orelse bun.getenvZ("HOME")) |data_dir| {
var paths = [_]string{".bunfig.toml"};
return resolve_path.joinAbsStringBufZ(data_dir, buf, &paths, .auto);
@@ -283,48 +284,88 @@ pub const Arguments = struct {
return null;
}
fn getRootBunJSONPath(buf: *[bun.MAX_PATH_BYTES]u8) ?[:0]const u8 {
if (bun.getenvZ("XDG_CONFIG_HOME") orelse bun.getenvZ("HOME")) |data_dir| {
var paths = [_]string{"bun.json"};
return resolve_path.joinAbsStringBufZ(data_dir, buf, &paths, .auto);
}
return null;
}
pub fn loadConfig(allocator: std.mem.Allocator, user_config_path_: ?string, ctx: *Command.Context, comptime cmd: Command.Tag) !void {
var config_buf: [bun.MAX_PATH_BYTES]u8 = undefined;
if (comptime cmd.readGlobalConfig()) {
if (!ctx.has_loaded_global_config) {
ctx.has_loaded_global_config = true;
if (comptime cmd.readGlobalConfig()) brk: {
if (ctx.has_loaded_global_config) break :brk;
if (getHomeConfigPath(&config_buf)) |path| {
try loadConfigPath(allocator, true, path, ctx, comptime cmd);
if (getRootBunJSONPath(&config_buf)) |path| {
Output.debug("trying to load {s}\n", .{path});
const success = loadConfigPath(allocator, true, path, ctx, comptime cmd) catch false;
if (success) {
Output.debug("successfully loaded global bun.json\n", .{});
ctx.has_loaded_global_config = true;
break :brk;
} else {
Output.debug("failed to load global bun.json\n", .{});
}
}
if (getRootBunfigPath(&config_buf)) |path| {
Output.debug("trying to load {s}\n", .{path});
const success = loadConfigPath(allocator, true, path, ctx, comptime cmd) catch false;
if (success) {
Output.debug("successfully loaded global bunfig\n", .{});
ctx.has_loaded_global_config = true;
break :brk;
} else {
Output.debug("failed to load global bunfig\n", .{});
}
}
}
var config_path: [:0]u8 = undefined;
var config_path_: []const u8 = user_config_path_ orelse "";
var auto_loaded: bool = false;
if (config_path_.len == 0 and (user_config_path_ != null or
Command.Tag.always_loads_config.get(cmd) or
(cmd == .AutoCommand and
// "bun"
(ctx.positionals.len == 0 or
// "bun file.js"
ctx.positionals.len > 0 and options.defaultLoaders.has(std.fs.path.extension(ctx.positionals[0]))))))
{
config_path_ = "bunfig.toml";
auto_loaded = true;
}
if (config_path_.len == 0) {
return;
}
defer ctx.debug.loaded_bunfig = true;
var config_path: [:0]u8 = undefined;
if (config_path_[0] == '/') {
// read user-specified config file if path is absolute
if (config_path_.len > 0 and config_path_[0] == '/') {
Output.debug("loading config from user-specified abs path\n", .{});
Output.debug("config_path_: {s}\n", .{config_path_});
@memcpy(config_buf[0..config_path_.len], config_path_);
config_buf[config_path_.len] = 0;
config_path = config_buf[0..config_path_.len :0];
} else {
if (ctx.args.absolute_working_dir == null) {
var secondbuf: [bun.MAX_PATH_BYTES]u8 = undefined;
var cwd = std.os.getcwd(&secondbuf) catch return;
ctx.args.absolute_working_dir = try allocator.dupe(u8, cwd);
var success = loadConfigPath(allocator, false, config_path, ctx, comptime cmd) catch false;
if (success) {
Output.debug("loaded user-specified file\n", .{});
defer ctx.debug.loaded_bunfig = true;
return;
} else {
Output.debug("failed to load user-specified file\n", .{});
}
}
var should_load_config = Command.Tag.always_loads_config.get(cmd) or
(cmd == .AutoCommand and
(ctx.positionals.len == 0 or ctx.positionals.len > 0 and options.defaultLoaders.has(std.fs.path.extension(ctx.positionals[0])))) or (cmd == .RunCommand and
(ctx.positionals.len == 2 and options.defaultLoaders.has(std.fs.path.extension(ctx.positionals[1]))));
// skip reading config
if (!should_load_config) {
Output.debug("skipping loading config\n", .{});
return;
}
// set absolute_working_dir
if (ctx.args.absolute_working_dir == null) {
var secondbuf: [bun.MAX_PATH_BYTES]u8 = undefined;
var cwd = std.os.getcwd(&secondbuf) catch return;
ctx.args.absolute_working_dir = try allocator.dupe(u8, cwd);
}
// load from user-specified path
Output.debug("config_path_: {s}\n", .{config_path_});
if (config_path_.len != 0) {
Output.debug("loading from path: {s}\n", .{config_path_});
var parts = [_]string{ ctx.args.absolute_working_dir.?, config_path_ };
config_path_ = resolve_path.joinAbsStringBuf(
ctx.args.absolute_working_dir.?,
@@ -334,9 +375,60 @@ pub const Arguments = struct {
);
config_buf[config_path_.len] = 0;
config_path = config_buf[0..config_path_.len :0];
var success = loadConfigPath(allocator, true, config_path, ctx, comptime cmd) catch false;
if (success) {
Output.debug("loaded user-specified file\n", .{});
defer ctx.debug.loaded_bunfig = true;
return;
} else {
Output.debug("failed to load user-specified file\n", .{});
}
}
try loadConfigPath(allocator, auto_loaded, config_path, ctx, comptime cmd);
var parts: [2]string = undefined;
// load bun.json if exists
parts = .{ ctx.args.absolute_working_dir.?, "bun.json" };
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];
Output.debug("loading local bun.json\n", .{});
var bun_json_loaded = loadConfigPath(allocator, true, config_path, ctx, comptime cmd) catch false;
if (bun_json_loaded) {
Output.debug("loaded local bun.json\n", .{});
defer ctx.debug.loaded_bunfig = true;
return;
} else {
Output.debug("failed to load bun.json\n", .{});
}
// load bunfig.toml if exists
parts = .{ ctx.args.absolute_working_dir.?, "bunfig.toml" };
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];
Output.debug("loading local bunfig.toml\n", .{});
var bunfig_loaded = loadConfigPath(allocator, true, config_path, ctx, comptime cmd) catch false;
if (bunfig_loaded) {
Output.debug("loaded local bunfig.toml\n", .{});
defer ctx.debug.loaded_bunfig = true;
return;
} else {
Output.debug("failed to load bunfig\n", .{});
}
return;
}
pub fn loadConfigWithCmdArgs(
@@ -1491,7 +1583,10 @@ pub const Command = struct {
if (extension.len > 0) {
if (!ctx.debug.loaded_bunfig) {
try bun.CLI.Arguments.loadConfigPath(ctx.allocator, true, "bunfig.toml", &ctx, .RunCommand);
var success = Arguments.loadConfigPath(ctx.allocator, true, "bun.json", &ctx, .RunCommand) catch false;
if (!success) {
_ = Arguments.loadConfigPath(ctx.allocator, true, "bunfig.toml", &ctx, .RunCommand) catch false;
}
}
if (ctx.preloads.len > 0)
@@ -1600,7 +1695,8 @@ pub const Command = struct {
var absolute_script_path = bun.getFdPath(file.handle, &script_name_buf) catch return false;
if (!ctx.debug.loaded_bunfig) {
bun.CLI.Arguments.loadConfigPath(ctx.allocator, true, "bunfig.toml", ctx, .RunCommand) catch {};
var success = Arguments.loadConfigPath(ctx.allocator, true, "bun.json", ctx, .RunCommand) catch false;
if (!success) _ = Arguments.loadConfigPath(ctx.allocator, true, "bunfig.toml", ctx, .RunCommand) catch false;
}
BunJS.Run.boot(

View File

@@ -933,7 +933,9 @@ pub const RunCommand = struct {
// once we know it's a file, check if they have any preloads
if (ext.len > 0 and !has_loader) {
if (!ctx.debug.loaded_bunfig) {
try bun.CLI.Arguments.loadConfigPath(ctx.allocator, true, "bunfig.toml", &ctx, .RunCommand);
_ = bun.CLI.Arguments.loadConfigPath(ctx.allocator, true, "bun.json", &ctx, .RunCommand) catch brk: {
break :brk bun.CLI.Arguments.loadConfigPath(ctx.allocator, true, "bunfig.toml", &ctx, .RunCommand) catch false;
};
}
if (ctx.preloads.len == 0)

View File

@@ -5722,7 +5722,7 @@ pub const PackageManager = struct {
"Possible values: \"hardlink\" (default), \"symlink\", \"copyfile\"";
const install_params_ = [_]ParamType{
clap.parseParam("-c, --config <STR>? Load config (bunfig.toml)") catch unreachable,
clap.parseParam("-c, --config <STR> Load config (bun.json)") catch unreachable,
clap.parseParam("-y, --yarn Write a yarn.lock file (yarn v1)") catch unreachable,
clap.parseParam("-p, --production Don't install devDependencies") catch unreachable,
clap.parseParam("--no-save Don't save a lockfile") catch unreachable,

128
test/cli/run/bunfig.test.ts Normal file
View File

@@ -0,0 +1,128 @@
import { describe, expect, test } from "bun:test";
import { bunRun, tempDirWithFiles } from "harness";
describe("config", () => {
test("read bun.json", () => {
{
const dir = tempDirWithFiles("dotenv", {
"bun.json": `{"define": { "caterpillar": "'butterfly'" }}`,
"index.ts": "console.log(caterpillar);",
});
const { stdout } = bunRun(`${dir}/index.ts`);
expect(stdout).toBe("butterfly");
}
});
test("read bunfig.toml", () => {
{
const dir = tempDirWithFiles("dotenv", {
"bunfig.toml": `[define]\n"caterpillar" = "'butterfly'"`,
"index.ts": "console.log(caterpillar);",
});
const { stdout } = bunRun(`${dir}/index.ts`);
expect(stdout).toBe("butterfly");
}
});
test("ignore bunfig.toml if bun.json is found", () => {
{
const dir = tempDirWithFiles("dotenv", {
"bun.json": `{"define": { "caterpillar": "'correct'" }}`,
"bunfig.toml": `[define]\n"caterpillar" = "'wrong'"`,
"index.ts": "console.log(caterpillar);",
});
const { stdout } = bunRun(`${dir}/index.ts`);
expect(stdout).toBe("correct");
}
});
test("read --config *.json", () => {
{
const dir = tempDirWithFiles("dotenv", {
"bun2.json": `{"define": { "caterpillar": "'butterfly'" }}`,
"index.ts": "console.log(caterpillar);",
});
const { stdout } = bunRun(`${dir}/index.ts`, {}, { flags: ["--config", "bun2.json"] });
expect(stdout).toBe("butterfly");
}
});
test("read -c *.json", () => {
{
const dir = tempDirWithFiles("dotenv", {
"bun2.json": `{"define": { "caterpillar": "'butterfly'" }}`,
"index.ts": "console.log(caterpillar);",
});
const { stdout } = bunRun(`${dir}/index.ts`, {}, { flags: ["-c", "bun2.json"] });
expect(stdout).toBe("butterfly");
}
});
test("read --config *.json absolute path", () => {
{
const dir = tempDirWithFiles("dotenv", {
"bun2.json": `{"define": { "caterpillar": "'butterfly'" }}`,
"index.ts": "console.log(caterpillar);",
});
const { stdout } = bunRun(`${dir}/index.ts`, {}, { flags: ["-c", `${dir}/bun2.json`] });
expect(stdout).toBe("butterfly");
}
});
test("read --config *.toml", () => {
{
const dir = tempDirWithFiles("dotenv", {
"bun2.toml": `[define]\n"caterpillar" = "'butterfly'"`,
"index.ts": "console.log(caterpillar);",
});
const { stdout } = bunRun(`${dir}/index.ts`, {}, { flags: ["--config", "bun2.toml"] });
expect(stdout).toBe("butterfly");
}
});
test("read -c *.toml", () => {
{
const dir = tempDirWithFiles("dotenv", {
"bun2.toml": `[define]\n"caterpillar" = "'butterfly'"`,
"index.ts": "console.log(caterpillar);",
});
const { stdout } = bunRun(`${dir}/index.ts`, {}, { flags: ["-c", "bun2.toml"] });
expect(stdout).toBe("butterfly");
}
});
test("read --config absolute path", () => {
{
const dir = tempDirWithFiles("dotenv", {
"bun2.toml": `[define]\n"caterpillar" = "'butterfly'"`,
"index.ts": "console.log(caterpillar);",
});
const { stdout } = bunRun(`${dir}/index.ts`, {}, { flags: ["-c", `${dir}/bun2.toml`] });
expect(stdout).toBe("butterfly");
}
});
test("fail if --config absolute path can't be found", () => {
{
const dir = tempDirWithFiles("dotenv", {
"index.ts": "console.log(caterpillar);",
});
{
expect(() => {
bunRun(`${dir}/index.ts`, {}, { flags: ["-c", `${dir}/notreal.json`] });
}).toThrow();
}
}
});
// test("read --config absolute path", () => {
// {
// const dir = tempDirWithFiles("dotenv", {
// "bun2.toml": `[define]\n"caterpillar" = "'butterfly'"`,
// "index.ts": "console.log(caterpillar);",
// });
// const { stdout } = bunRun(`${dir}/index.ts`, {}, { flags: ["-c", "bun2.toml"] });
// expect(stdout).toBe("butterfly");
// }
// });
});

View File

@@ -101,9 +101,15 @@ export function tempDirWithFiles(basename: string, files: Record<string, string
return dir;
}
export function bunRun(file: string, env?: Record<string, string>) {
export function bunRun(
file: string,
env?: Record<string, string>,
params?: {
flags?: string[];
},
) {
var path = require("path");
const result = Bun.spawnSync([bunExe(), file], {
const result = Bun.spawnSync([bunExe(), ...(params?.flags ?? []), file], {
cwd: path.dirname(file),
env: {
...bunEnv,
@@ -113,6 +119,7 @@ export function bunRun(file: string, env?: Record<string, string>) {
});
if (!result.success) throw new Error(result.stderr.toString("utf8"));
return {
code: result.exitCode,
stdout: result.stdout.toString("utf8").trim(),
stderr: result.stderr.toString("utf8").trim(),
};
@@ -148,6 +155,7 @@ export function bunRunAsScript(dir: string, script: string, env?: Record<string,
if (!result.success) throw new Error(result.stderr.toString("utf8"));
return {
code: result.exitCode,
stdout: result.stdout.toString("utf8").trim(),
stderr: result.stderr.toString("utf8").trim(),
};