Skip to content

Commit a6ad3b9

Browse files
authored
add --elide-lines override flag for workspace filtering (#15837)
1 parent b63a6c8 commit a6ad3b9

File tree

4 files changed

+134
-6
lines changed

4 files changed

+134
-6
lines changed

src/bunfig.zig

+8
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,14 @@ pub const Bunfig = struct {
597597
}
598598
}
599599

600+
if (run_expr.get("elide-lines")) |elide_lines| {
601+
if (elide_lines.data == .e_number) {
602+
this.ctx.bundler_options.elide_lines = @intFromFloat(elide_lines.data.e_number.value);
603+
} else {
604+
try this.addError(elide_lines.loc, "Expected number");
605+
}
606+
}
607+
600608
if (run_expr.get("shell")) |shell| {
601609
if (shell.asString(allocator)) |value| {
602610
if (strings.eqlComptime(value, "bun")) {

src/cli.zig

+21-1
Original file line numberDiff line numberDiff line change
@@ -243,13 +243,15 @@ pub const Arguments = struct {
243243
const auto_only_params = [_]ParamType{
244244
// clap.parseParam("--all") catch unreachable,
245245
clap.parseParam("--silent Don't print the script command") catch unreachable,
246+
clap.parseParam("--elide-lines <NUMBER> Number of lines of script output shown when using --filter (default: 10). Set to 0 to show all lines.") catch unreachable,
246247
clap.parseParam("-v, --version Print version and exit") catch unreachable,
247248
clap.parseParam("--revision Print version with revision and exit") catch unreachable,
248249
} ++ auto_or_run_params;
249250
pub const auto_params = auto_only_params ++ runtime_params_ ++ transpiler_params_ ++ base_params_;
250251

251252
const run_only_params = [_]ParamType{
252253
clap.parseParam("--silent Don't print the script command") catch unreachable,
254+
clap.parseParam("--elide-lines <NUMBER> Number of lines of script output shown when using --filter (default: 10). Set to 0 to show all lines.") catch unreachable,
253255
} ++ auto_or_run_params;
254256
pub const run_params = run_only_params ++ runtime_params_ ++ transpiler_params_ ++ base_params_;
255257

@@ -501,6 +503,15 @@ pub const Arguments = struct {
501503

502504
if (cmd == .RunCommand or cmd == .AutoCommand) {
503505
ctx.filters = args.options("--filter");
506+
507+
if (args.option("--elide-lines")) |elide_lines| {
508+
if (elide_lines.len > 0) {
509+
ctx.bundler_options.elide_lines = std.fmt.parseInt(usize, elide_lines, 10) catch {
510+
Output.prettyErrorln("<r><red>error<r>: Invalid elide-lines: \"{s}\"", .{elide_lines});
511+
Global.exit(1);
512+
};
513+
}
514+
}
504515
}
505516

506517
if (cmd == .TestCommand) {
@@ -1106,6 +1117,15 @@ pub const Arguments = struct {
11061117
ctx.debug.silent = true;
11071118
}
11081119

1120+
if (args.option("--elide-lines")) |elide_lines| {
1121+
if (elide_lines.len > 0) {
1122+
ctx.bundler_options.elide_lines = std.fmt.parseInt(usize, elide_lines, 10) catch {
1123+
Output.prettyErrorln("<r><red>error<r>: Invalid elide-lines: \"{s}\"", .{elide_lines});
1124+
Global.exit(1);
1125+
};
1126+
}
1127+
}
1128+
11091129
if (opts.define) |define| {
11101130
if (define.keys.len > 0)
11111131
bun.JSC.RuntimeTranspilerCache.is_disabled = true;
@@ -1513,7 +1533,7 @@ pub const Command = struct {
15131533

15141534
env_behavior: Api.DotEnvBehavior = .disable,
15151535
env_prefix: []const u8 = "",
1516-
1536+
elide_lines: ?usize = null,
15171537
// Compile options
15181538
compile: bool = false,
15191539
compile_target: Cli.CompileTarget = .{},

src/cli/filter_run.zig

+12-2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ const ScriptConfig = struct {
2929
// ../../node_modules/.bin
3030
// and so forth, in addition to the user's $PATH.
3131
PATH: []const u8,
32+
elide_count: ?usize,
3233

3334
fn cmp(_: void, a: @This(), b: @This()) bool {
3435
return bun.strings.cmpStringsAsc({}, a.package_name, b.package_name);
@@ -247,7 +248,7 @@ const State = struct {
247248
if (data[data.len - 1] == '\n') {
248249
data = data[0 .. data.len - 1];
249250
}
250-
if (max_lines == null) return .{ .content = data, .elided_count = 0 };
251+
if (max_lines == null or max_lines.? == 0) return .{ .content = data, .elided_count = 0 };
251252
var i: usize = data.len;
252253
var lines: usize = 0;
253254
while (i > 0) : (i -= 1) {
@@ -282,7 +283,9 @@ const State = struct {
282283
}
283284
for (this.handles) |*handle| {
284285
// normally we truncate the output to 10 lines, but on abort we print everything to aid debugging
285-
const e = elide(handle.buffer.items, if (is_abort) null else 10);
286+
const elide_lines = if (is_abort) null else handle.config.elide_count orelse 10;
287+
const e = elide(handle.buffer.items, elide_lines);
288+
286289
try this.draw_buf.writer().print(fmt("<b>{s}<r> {s} $ <d>{s}<r>\n"), .{ handle.config.package_name, handle.config.script_name, handle.config.script_content });
287290
if (e.elided_count > 0) {
288291
try this.draw_buf.writer().print(
@@ -513,6 +516,7 @@ pub fn runScriptsWithFilter(ctx: Command.Context) !noreturn {
513516
.combined = copy_script.items[0 .. copy_script.items.len - 1 :0],
514517
.deps = pkgjson.dependencies,
515518
.PATH = PATH,
519+
.elide_count = ctx.bundler_options.elide_lines,
516520
});
517521
}
518522
}
@@ -536,6 +540,12 @@ pub fn runScriptsWithFilter(ctx: Command.Context) !noreturn {
536540
.env = this_transpiler.env,
537541
};
538542

543+
// Check if elide-lines is used in a non-terminal environment
544+
if (ctx.bundler_options.elide_lines != null and !state.pretty_output) {
545+
Output.prettyErrorln("<r><red>error<r>: --elide-lines is only supported in terminal environments", .{});
546+
Global.exit(1);
547+
}
548+
539549
// initialize the handles
540550
var map = bun.StringHashMap(std.ArrayList(*ProcessHandle)).init(ctx.allocator);
541551
for (scripts.items, 0..) |*script, i| {

test/cli/run/filter-workspace.test.ts

+93-3
Original file line numberDiff line numberDiff line change
@@ -86,29 +86,41 @@ function runInCwdSuccess({
8686
antipattern,
8787
command = ["present"],
8888
auto = false,
89+
env = {},
90+
elideCount,
8991
}: {
9092
cwd: string;
9193
pattern: string | string[];
9294
target_pattern: RegExp | RegExp[];
9395
antipattern?: RegExp | RegExp[];
9496
command?: string[];
9597
auto?: boolean;
98+
env?: Record<string, string | undefined>;
99+
elideCount?: number;
96100
}) {
97101
const cmd = auto ? [bunExe()] : [bunExe(), "run"];
102+
103+
// Add elide-lines first if specified
104+
if (elideCount !== undefined) {
105+
cmd.push("--elide-lines", elideCount.toString());
106+
}
107+
98108
if (Array.isArray(pattern)) {
99109
for (const p of pattern) {
100110
cmd.push("--filter", p);
101111
}
102112
} else {
103113
cmd.push("--filter", pattern);
104114
}
115+
105116
for (const c of command) {
106117
cmd.push(c);
107118
}
119+
108120
const { exitCode, stdout, stderr } = spawnSync({
109-
cwd: cwd,
110-
cmd: cmd,
111-
env: bunEnv,
121+
cwd,
122+
cmd,
123+
env: { ...bunEnv, ...env },
112124
stdout: "pipe",
113125
stderr: "pipe",
114126
});
@@ -416,4 +428,82 @@ describe("bun", () => {
416428
expect(stdoutval).toMatch(/code 23/);
417429
expect(exitCode).toBe(23);
418430
});
431+
432+
function runElideLinesTest({
433+
elideLines,
434+
target_pattern,
435+
antipattern,
436+
win32ExpectedError,
437+
}: {
438+
elideLines: number;
439+
target_pattern: RegExp[];
440+
antipattern?: RegExp[];
441+
win32ExpectedError: RegExp;
442+
}) {
443+
const dir = tempDirWithFiles("testworkspace", {
444+
packages: {
445+
dep0: {
446+
"index.js": Array(20).fill("console.log('log_line');").join("\n"),
447+
"package.json": JSON.stringify({
448+
name: "dep0",
449+
scripts: {
450+
script: `${bunExe()} run index.js`,
451+
},
452+
}),
453+
},
454+
},
455+
"package.json": JSON.stringify({
456+
name: "ws",
457+
workspaces: ["packages/*"],
458+
}),
459+
});
460+
461+
if (process.platform === "win32") {
462+
const { exitCode, stderr } = spawnSync({
463+
cwd: dir,
464+
cmd: [bunExe(), "run", "--filter", "./packages/dep0", "--elide-lines", String(elideLines), "script"],
465+
env: { ...bunEnv, FORCE_COLOR: "1", NO_COLOR: "0" },
466+
stdout: "pipe",
467+
stderr: "pipe",
468+
});
469+
expect(stderr.toString()).toMatch(win32ExpectedError);
470+
expect(exitCode).not.toBe(0);
471+
return;
472+
}
473+
474+
runInCwdSuccess({
475+
cwd: dir,
476+
pattern: "./packages/dep0",
477+
env: { FORCE_COLOR: "1", NO_COLOR: "0" },
478+
target_pattern,
479+
antipattern,
480+
command: ["script"],
481+
elideCount: elideLines,
482+
});
483+
}
484+
485+
test("elides output by default when using --filter", () => {
486+
runElideLinesTest({
487+
elideLines: 10,
488+
target_pattern: [/\[10 lines elided\]/, /(?:log_line[\s\S]*?){20}/],
489+
win32ExpectedError: /--elide-lines is only supported in terminal environments/,
490+
});
491+
});
492+
493+
test("respects --elide-lines argument", () => {
494+
runElideLinesTest({
495+
elideLines: 15,
496+
target_pattern: [/\[5 lines elided\]/, /(?:log_line[\s\S]*?){20}/],
497+
win32ExpectedError: /--elide-lines is only supported in terminal environments/,
498+
});
499+
});
500+
501+
test("--elide-lines=0 shows all output", () => {
502+
runElideLinesTest({
503+
elideLines: 0,
504+
target_pattern: [/(?:log_line[\s\S]*?){20}/],
505+
antipattern: [/lines elided/],
506+
win32ExpectedError: /--elide-lines is only supported in terminal environments/,
507+
});
508+
});
419509
});

0 commit comments

Comments
 (0)