linera-io/linera-protocol

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

Open

Aperta il 10 apr 2026

Vedi su GitHub
 (0 commenti) (0 reazioni) (0 assegnatari)Rust (32.149 star) (2354 fork)batch import
enhancementgood first issueux

Descrizione

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.

Guida contributor