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

Support NO_COLOR environment variable #3055

Merged
merged 4 commits into from
Jun 2, 2023
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
30 changes: 27 additions & 3 deletions docs/runtime/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 %}

## Configure `bun install`

Expand Down
5 changes: 3 additions & 2 deletions src/bundler.zig
Original file line number Diff line number Diff line change
Expand Up @@ -529,8 +529,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;
}
}
Expand Down
64 changes: 33 additions & 31 deletions src/output.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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;
Expand Down
35 changes: 35 additions & 0 deletions test/cli/bun.test.ts
Original file line number Diff line number Diff line change
@@ -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/);
});
}
});
});