linera-io/linera-protocol

CLI: respect NO_COLOR and never emit ANSI escape codes to stdout

Open

#5980 opened on Apr 10, 2026

View on GitHub
 (0 comments) (0 reactions) (0 assignees)Rust (32,149 stars) (2,354 forks)batch import
enhancementgood first issueux

Description

Parent: linera-io/linera-protocol#5977 (Tier 1 item 4)

Problem

The colored crate is used to emit ANSI escape codes in the linera CLI output. Two concrete issues:

  1. ANSI codes leak to stdout in net up (linera-service/src/cli/net_up_utils.rs:311-330). The command prints shell export statements wrapped in .bold(), which emit ANSI escape codes when rendered. Stdout should always be clean text suitable for parsing or piping — never formatted.
  2. NO_COLOR / CLICOLOR environment variables are not explicitly honored. The colored crate auto-detects TTY but its behavior when piped is not guaranteed to produce clean output, and there's no documented environment override.

Relevant existing usages:

  • linera-service/src/cli/net_up_utils.rs:6use colored::Colorize as _;
  • linera-service/src/cli/net_up_utils.rs:317,325,329.bold() calls on stdout println!s for export LINERA_WALLET=... etc.
  • linera-service/src/cli/main.rs:36use colored::Colorize;
  • linera-service/src/cli/main.rs:1473info!("{}", "Application created successfully!".green().bold());
  • linera-service/src/cli/main.rs:1525info!("{}", "Application published successfully!".green().bold());
  • linera-service/src/cli/main.rs:1599 — same pattern.

Requirements

  1. Stdout must never contain ANSI escape codes. Any println! / print! must emit plain text, regardless of TTY status or color settings.
  2. Stderr (via tracing) may emit color when stderr is a TTY and colors are not disabled.
  3. NO_COLOR=1, CLICOLOR=0, and NO_COLOR set to any non-empty value must disable all color output on stderr as well. Follow the NO_COLOR specification.
  4. CLICOLOR_FORCE=1 should force color output even when stderr is not a TTY.

Proposed implementation

For net up (stdout fix):

In linera-service/src/cli/net_up_utils.rs:311-330, remove the .bold() calls. Stdout should be plain:

println!("export LINERA_WALLET=\"{}\"", client.wallet_path().display());
println!("export LINERA_KEYSTORE=\"{}\"", client.keystore_path().display());
println!("export LINERA_STORAGE=\"{}\"", client.storage_path());

The explanatory message at line 306-310 uses eprintln! already, which is correct. If the human wants a bold "HERE IS YOUR CONFIG" banner, it goes on stderr, not stdout.

For NO_COLOR support (stderr):

Early in main() (around linera-service/src/cli/main.rs:1938), check the relevant env vars and call colored::control::set_override(false) if colors should be disabled. The colored crate already reads NO_COLOR on first use, but being explicit ensures consistent behavior. Reference: https://docs.rs/colored/latest/colored/control/fn.set_override.html

fn configure_colors() {
    use std::env;
    let no_color = env::var_os("NO_COLOR").is_some_and(|v| !v.is_empty());
    let clicolor_zero = env::var("CLICOLOR").ok().as_deref() == Some("0");
    if no_color || clicolor_zero {
        colored::control::set_override(false);
    } else if env::var("CLICOLOR_FORCE").ok().as_deref() == Some("1") {
        colored::control::set_override(true);
    }
}

Call it once at the top of main(). This also affects the .green().bold() calls in main.rs:1473/1525/1599 since those go through tracing, which writes to stderr.

Backwards compatibility

Removing bold from net up stdout is strictly a visual change for humans. The text content is identical. Scripts doing eval "$(linera net up ...)" were already broken by the ANSI codes in some shell configurations — this makes eval actually work consistently.

Testing

Unit test (add to linera-service/src/cli/net_up_utils.rs under #[cfg(test)] mod tests):

Not straightforward since net up is a daemon. Instead, verify via E2E test in linera-service/tests/linera_net_tests.rs:

  • Run linera net up --with-faucet as a subprocess, capture stdout, assert it contains export LINERA_WALLET= (plain text), assert it does not contain any \x1b[ (ANSI escape) sequences.
  • Run with NO_COLOR=1 env var, assert no ANSI sequences anywhere (stdout or stderr).

Manual verification:

cargo build -p linera-service --bin linera

# Should print plain text to stdout, no ANSI codes
./target/debug/linera net up --with-faucet --faucet-port 8080 2>/dev/null | cat -v
# Look for any '^[' sequences — there should be none in stdout.

# NO_COLOR should also strip colors from stderr
NO_COLOR=1 ./target/debug/linera transfer ... 2>&1 | cat -v
# No ANSI codes anywhere.

Definition of done

  • net up stdout contains no ANSI escape codes.
  • NO_COLOR=1 and CLICOLOR=0 disable colors on stderr.
  • CLICOLOR_FORCE=1 forces colors even when stderr is not a TTY.
  • E2E test verifies clean stdout (no ANSI) from net up.
  • cargo clippy --all-targets --all-features -- -D warnings passes.
  • cargo fmt applied.
  • Manual verification with cat -v to confirm no escape sequences.

Good first issue

Medium-small change. Touches two files. No architectural questions. Good candidate for a newcomer with basic Rust familiarity.

Contributor guide