Retaining output colors when shelling out to node
Asked Answered
D

5

21

I have a little Grunt task that shells out via node and runs "composer install".

var done = this.async();

var exec = require('child_process').exec;
var composer = exec(
    'php bin/composer.phar install',
    function(error, stdout, stderr) {
        done(error===null);
    }
);

composer.stdout.on(
    'data',
    grunt.log.write
);

As you can see, I'm outputting the stdout of this child process to grunt.log. All output is showing up nice and well as expected, except that the output is all in my default console color. If I run "composer install" directly I get highlighting that improves readability.

Since I'm new to node, Grunt and shelling out in general, I'm unsure about in which part of the system the coloring gets lost, or even how to debug this efficiently.

Deth answered 16/9, 2013 at 10:13 Comment(0)
S
7

In some cases command line programs will prevent a colorized output when not run through a terminal, and thus you need to instruct the program to output the ANSI escape sequences.

In this case, it's as simple as adding an '--ansi' flag, for example:

var done = this.async();

var exec = require('child_process').exec;
var composer = exec(
    'php bin/composer.phar install --ansi',
    function(error, stdout, stderr) {
        done(error===null);
    }
);

composer.stdout.on(
    'data',
    grunt.log.write
);
Sissie answered 16/9, 2013 at 14:20 Comment(3)
Good to know, interested to know if it worked (can't test it right now)!Burtis
Does --ansi only apply to the php CLI command in this case? Or is that some universal param that works with any command?Mensch
@bigp this only applies to the php command (in fact it's a composer argument, not a php argument)Sissie
S
36

Using spawn with the option stdio='inherit' worked to include output color.

From the documentation:

options (Object)

  • cwd String Current working directory of the child process
  • stdio (Array|String) Child's stdio configuration. (See below)

...

As a shorthand, the stdio argument may also be one of the following strings, rather than an array:

  • ignore - ['ignore', 'ignore', 'ignore']
  • pipe - ['pipe', 'pipe', 'pipe']
  • inherit - [process.stdin, process.stdout, process.stderr] or [0,1,2]

Here is an example of the working code:

require('child_process')
  .spawn('npm', ['install'], {stdio:'inherit'})
  .on('exit', function (error) {

    if(!error){
      console.log('Success!');
    }

    }
  });

I wanted to make exec work but I did not find a way to access the same option.

Spinoza answered 22/11, 2013 at 12:39 Comment(2)
This is correct. But it unfortunately also means that you cannot capture the output. inherit just prints it out and that's all.Iddo
@Marc If you want to still capture the output, then use {stdio:'pipe'} as the 3rd parameter of spawn(). In order to allow color to be shown, do this: var colors = require('colors'); colors.enabled = true;.Flamenco
L
10

The --colors flag worked for me. Node version 6.8.0...

--colors, -c force enabling of colors [boolean]

The following generic example would print the colors should any be returned...

var exec = require('child_process').exec;

exec('node someCommand --colors', function (error, stdout, stderr) {

  console.log(stdout || stderr); // yay colors!
});
Lath answered 19/1, 2017 at 19:55 Comment(2)
simple and modern - guys, you need to be using this solution!Informative
The OP is not executing a node command (they're spawning a php process). So this is not a solution. Moreover, --colors is no longer an option for node.Absolute
S
7

In some cases command line programs will prevent a colorized output when not run through a terminal, and thus you need to instruct the program to output the ANSI escape sequences.

In this case, it's as simple as adding an '--ansi' flag, for example:

var done = this.async();

var exec = require('child_process').exec;
var composer = exec(
    'php bin/composer.phar install --ansi',
    function(error, stdout, stderr) {
        done(error===null);
    }
);

composer.stdout.on(
    'data',
    grunt.log.write
);
Sissie answered 16/9, 2013 at 14:20 Comment(3)
Good to know, interested to know if it worked (can't test it right now)!Burtis
Does --ansi only apply to the php CLI command in this case? Or is that some universal param that works with any command?Mensch
@bigp this only applies to the php command (in fact it's a composer argument, not a php argument)Sissie
C
5

If like myself, you are spawning a child node process as opposed to a non-node script, you may find that the --ansi and --color options will give you little success for retaining the colored output of child node processes.

Instead, you should inherit the instances of stdio of the current process.

My particular use-case involved forking a node server as a background task in order to execute an end-to-end test suite against an active HTTP interface. Here was my final solution:

var child = spawn('node', ['webserver/server.js'], {
  args: ['--debug'],
  env: _.extend(process.env, {
    MOCK_API: mockApi
  }),

  // use process.stdout to retain ansi color codes
  stdio: [process.stdin, process.stdout, 'pipe']
});

// use custom error buffer in order to throw using grunt.fail()
var errorBuffer = '';
child.stderr.on('data', function(data) {
  errorBuffer += data;
});

child.on('close', function(code) {
  if (code) {
    grunt.fail.fatal(errorBuffer, code);
  } else {
    done();
  }
});
Constabulary answered 15/1, 2016 at 18:36 Comment(1)
The OP is not executing a node command (they're spawning a php process). So this is not a solution. Moreover, --colors is no longer an option for node.Absolute
S
0

I was there too. If you:

  • Don't want to inherit the child stdout
  • Don't know which command is going to be executed (then you don't know which of e.g --ansi or --colors can work)

Then you should spawn a PTY from node. I made this node package for this exact reason.

Shrader answered 31/12, 2021 at 21:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.