aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Ashcon Partovi <ashcon@partovi.net> 2023-06-02 14:24:16 -0700
committerGravatar GitHub <noreply@github.com> 2023-06-02 14:24:16 -0700
commitbfd315fc72749ecd98150de110f2a9cc586c7293 (patch)
treef31eb78df5d01a683c3022ce04a122d1dbf6e81e
parent72c2123e07c936d1c279c5f4effb096f24bc1f58 (diff)
downloadbun-bfd315fc72749ecd98150de110f2a9cc586c7293.tar.gz
bun-bfd315fc72749ecd98150de110f2a9cc586c7293.tar.zst
bun-bfd315fc72749ecd98150de110f2a9cc586c7293.zip
Support `NO_COLOR` environment variable (#3055)
-rw-r--r--docs/runtime/configuration.md30
-rw-r--r--src/bundler.zig5
-rw-r--r--src/output.zig64
-rw-r--r--test/cli/bun.test.ts35
4 files changed, 98 insertions, 36 deletions
diff --git a/docs/runtime/configuration.md b/docs/runtime/configuration.md
index 83a6ae37f..8dc2bfe24 100644
--- a/docs/runtime/configuration.md
+++ b/docs/runtime/configuration.md
@@ -14,10 +14,34 @@ If both a global and local `bunfig` are detected, the results are shallow-merged
## Environment variables
-<!-- - `GOMAXPROCS`: For `bun bun`, this sets the maximum number of threads to use. If you’re experiencing an issue with `bun bun`, try setting `GOMAXPROCS=1` to force Bun to run single-threaded -->
+These environment variables are checked by Bun to detect functionality and toggle features.
-- `DISABLE_BUN_ANALYTICS=1` this disables Bun's analytics. Bun records bundle timings (so we can answer with data, "is Bun getting faster?") and feature usage (e.g., "are people actually using macros?"). The request body size is about 60 bytes, so it’s not a lot of data
-- `TMPDIR`: Bun occasionally requires a directory to store intermediate assets during bundling or other operations. If unset, `TMPDIR` defaults to the platform-specific temporary directory (on Linux, `/tmp` and on macOS `/private/tmp`).
+{% table %}
+
+- Name
+- Description
+
+---
+
+- `TMPDIR`
+- Bun occasionally requires a directory to store intermediate assets during bundling or other operations. If unset, defaults to the platform-specific temporary directory: `/tmp` on Linux, `/private/tmp` on macOS.
+
+---
+
+- `NO_COLOR`
+- If `NO_COLOR=1`, then ANSI color output is [disabled](https://no-color.org/).
+
+---
+
+- `FORCE_COLOR`
+- If `FORCE_COLOR=1`, then ANSI color output is force enabled, even if `NO_COLOR` is set.
+
+---
+
+- `DO_NOT_TRACK`
+- If `DO_NOT_TRACK=1`, then analytics are [disabled](https://do-not-track.dev/). Bun records bundle timings (so we can answer with data, "is Bun getting faster?") and feature usage (e.g., "are people actually using macros?"). The request body size is about 60 bytes, so it's not a lot of data.
+
+{% /table %}
## Runtime
diff --git a/src/bundler.zig b/src/bundler.zig
index ea8222870..c2cec56c1 100644
--- a/src/bundler.zig
+++ b/src/bundler.zig
@@ -532,8 +532,9 @@ pub const Bundler = struct {
else => {},
}
- if (this.env.map.get("DISABLE_BUN_ANALYTICS")) |should_disable| {
- if (strings.eqlComptime(should_disable, "1")) {
+ if (this.env.map.get("DO_NOT_TRACK")) |dnt| {
+ // https://do-not-track.dev/
+ if (strings.eqlComptime(dnt, "1")) {
Analytics.disabled = true;
}
}
diff --git a/src/output.zig b/src/output.zig
index a37a58abf..683e39164 100644
--- a/src/output.zig
+++ b/src/output.zig
@@ -95,29 +95,32 @@ pub const Source = struct {
}
pub fn isNoColor() bool {
- return bun.getenvZ("NO_COLOR") != null;
+ const no_color = bun.getenvZ("NO_COLOR") orelse return false;
+ // https://no-color.org/
+ // "when present and not an empty string (regardless of its value)"
+ return no_color.len != 0;
}
- pub fn isForceColor() ?bool {
- const force_color_str = bun.getenvZ("FORCE_COLOR") orelse return null;
- return force_color_str.len == 0 or
- strings.eqlComptime(force_color_str, "TRUE") or
- strings.eqlComptime(force_color_str, "ON") or
- strings.eqlComptime(force_color_str, "YES") or
- strings.eqlComptime(force_color_str, "1") or
- strings.eqlComptime(force_color_str, " ");
+ pub fn isForceColor() bool {
+ const force_color = bun.getenvZ("FORCE_COLOR") orelse return false;
+ // Supported by Node.js, if set will ignore NO_COLOR.
+ // - "1", "true", or "" to indicate 16-color support
+ // - "2" to indicate 256-color support
+ // - "3" to indicate 16 million-color support
+ return force_color.len == 0 or
+ strings.eqlComptime(force_color, "1") or
+ strings.eqlComptime(force_color, "true") or
+ strings.eqlComptime(force_color, "2") or
+ strings.eqlComptime(force_color, "3");
}
pub fn isColorTerminal() bool {
- if (isForceColor()) |val| return val;
- if (bun.getenvZ("COLORTERM")) |color_term| return !strings.eqlComptime(color_term, "0");
-
+ if (bun.getenvZ("COLORTERM")) |color_term| {
+ return !strings.eqlComptime(color_term, "0");
+ }
if (bun.getenvZ("TERM")) |term| {
- if (strings.eqlComptime(term, "dumb")) return false;
-
- return true;
+ return !strings.eqlComptime(term, "dumb");
}
-
return false;
}
@@ -128,27 +131,26 @@ pub const Source = struct {
if (!stdout_stream_set) {
stdout_stream_set = true;
if (comptime Environment.isNative) {
- var is_color_terminal: ?bool = null;
- if (_source.stream.isTty()) {
+ var enable_color: ?bool = null;
+ if (isForceColor()) {
+ enable_color = true;
+ } else if (isNoColor() or !isColorTerminal()) {
+ enable_color = false;
+ }
+
+ const is_stdout_tty = _source.stream.isTty();
+ if (is_stdout_tty) {
stdout_descriptor_type = OutputStreamDescriptor.terminal;
- enable_ansi_colors_stdout = isColorTerminal();
- is_color_terminal = enable_ansi_colors_stdout;
- } else if (isForceColor()) |val| {
- enable_ansi_colors_stdout = val;
- } else {
- enable_ansi_colors_stdout = false;
}
- if (_source.error_stream.isTty()) {
+ const is_stderr_tty = _source.error_stream.isTty();
+ if (is_stderr_tty) {
stderr_descriptor_type = OutputStreamDescriptor.terminal;
- enable_ansi_colors_stderr = is_color_terminal orelse isColorTerminal();
- } else if (isForceColor()) |val| {
- enable_ansi_colors_stderr = val;
- } else {
- enable_ansi_colors_stderr = false;
}
- enable_ansi_colors = enable_ansi_colors_stderr or enable_ansi_colors_stdout;
+ enable_ansi_colors_stdout = enable_color orelse is_stdout_tty;
+ enable_ansi_colors_stderr = enable_color orelse is_stderr_tty;
+ enable_ansi_colors = enable_ansi_colors_stdout or enable_ansi_colors_stderr;
}
stdout_stream = _source.stream;
diff --git a/test/cli/bun.test.ts b/test/cli/bun.test.ts
new file mode 100644
index 000000000..97ea52ecd
--- /dev/null
+++ b/test/cli/bun.test.ts
@@ -0,0 +1,35 @@
+import { describe, test, expect } from "bun:test";
+import { spawnSync } from "bun";
+import { bunExe } from "harness";
+
+describe("bun", () => {
+ describe("NO_COLOR", () => {
+ for (const value of ["1", "0", "foo", " "]) {
+ test(`respects NO_COLOR=${JSON.stringify(value)} to disable color`, () => {
+ const { stdout } = spawnSync({
+ cmd: [bunExe()],
+ env: {
+ NO_COLOR: value,
+ },
+ });
+ expect(stdout.toString()).not.toMatch(/\u001b\[\d+m/);
+ });
+ }
+ for (const value of ["", undefined]) {
+ // TODO: need a way to fake a tty in order to test this,
+ // and cannot use FORCE_COLOR since that will always override NO_COLOR.
+ test.todo(`respects NO_COLOR=${JSON.stringify(value)} to enable color`, () => {
+ const { stdout } = spawnSync({
+ cmd: [bunExe()],
+ env:
+ value === undefined
+ ? {}
+ : {
+ NO_COLOR: value,
+ },
+ });
+ expect(stdout.toString()).toMatch(/\u001b\[\d+m/);
+ });
+ }
+ });
+});