Skip to content

Commit

Permalink
colors, piping, utf8 characters, stream overrides (#1749)
Browse files Browse the repository at this point in the history
* handle colors and platform piping

- pipe stderr to ignore high sierra fixes #1745,
- always pipe windows for utf8 encoding fixes #1143 and #1550
- force color in CI by default #1747
- support NO_COLOR argument #1748

* reset TTY for stdin and stdout not just stderr

* fix for failing tests in ci

* fix failing environment unit tests due to sinon env change

* fix failing integration request specs

* fix failing tests, cleanup cache before each test, not after

* fix failing integration server tests
  • Loading branch information
brian-mann committed May 20, 2018
1 parent 1d0b35b commit d154739
Show file tree
Hide file tree
Showing 11 changed files with 389 additions and 199 deletions.
69 changes: 34 additions & 35 deletions cli/lib/exec/spawn.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
const _ = require('lodash')
const os = require('os')
const cp = require('child_process')
const tty = require('tty')
const path = require('path')
const Promise = require('bluebird')
const debug = require('debug')('cypress:cli')
Expand All @@ -11,15 +10,30 @@ const state = require('../tasks/state')
const xvfb = require('./xvfb')
const { throwFormErrorText, errors } = require('../errors')

const isXlibOrLibudevRe = /^(Xlib|libudev)/
const isXlibOrLibudevRe = /^(?:Xlib|libudev)/
const isHighSierraWarningRe = /\*\*\* WARNING/

function needsStderrPipe (needsXvfb) {
return needsXvfb && os.platform() === 'linux'
function isPlatform (platform) {
return os.platform() === platform
}

function needsStderrPiped (needsXvfb) {
return isPlatform('darwin') || (needsXvfb && isPlatform('linux'))
}

function needsEverythingPipedDirectly () {
return isPlatform('win32')
}

function getStdio (needsXvfb) {
if (needsEverythingPipedDirectly()) {
return 'pipe'
}

// https://github.com/cypress-io/cypress/issues/921
if (needsStderrPipe(needsXvfb)) {
// https://github.com/cypress-io/cypress/issues/1143
// https://github.com/cypress-io/cypress/issues/1745
if (needsStderrPiped(needsXvfb)) {
// returning pipe here so we can massage stderr
// and remove garbage from Xlib and libuv
// due to starting the XVFB process on linux
Expand All @@ -37,19 +51,20 @@ module.exports = {
if (process.env.CYPRESS_RUN_BINARY) {
executable = process.env.CYPRESS_RUN_BINARY
}

debug('needs XVFB?', needsXvfb)

// always push cwd into the args
args = [].concat(args, '--cwd', process.cwd())

_.defaults(options, {
env: process.env,
detached: false,
stdio: getStdio(needsXvfb),
})

const spawn = () => {
return new Promise((resolve, reject) => {

if (options.dev) {
// if we're in dev then reset
// the launch cmd to be 'npm run dev'
Expand All @@ -64,42 +79,25 @@ module.exports = {
options = _.omit(options, 'dev')
options = _.omit(options, 'binaryFolder')

// when running in electron in windows
// it never supports color but we're
// going to force it anyway as long
// as our parent cli process can support
// colors!
//
// also when we are in linux and using the 'pipe'
// option our process.stderr.isTTY will not be true
// which ends up disabling the colors =(
if (util.supportsColor()) {
process.env.FORCE_COLOR = '1'
process.env.DEBUG_COLORS = '1'
process.env.MOCHA_COLORS = '1'
}

// if we needed to pipe stderr and we're currently
// a tty on stderr
if (needsStderrPipe(needsXvfb) && tty.isatty(2)) {
// then force stderr tty
//
// this is necessary because we want our child
// electron browser to behave _THE SAME WAY_ as
// if we aren't using pipe. pipe is necessary only
// to filter out garbage on stderr -____________-
process.env.FORCE_STDERR_TTY = '1'
}
// figure out if we're going to be force enabling or disabling colors.
// also figure out whether we should force stdout and stderr into thinking
// it is a tty as opposed to a pipe.
options.env = _.extend({}, options.env, util.getEnvOverrides())

const child = cp.spawn(executable, args, options)
child.on('close', resolve)
child.on('error', reject)

child.stdin && child.stdin.pipe(process.stdin)
child.stdout && child.stdout.pipe(process.stdout)

// if this is defined then we are manually piping for linux
// to filter out the garbage
child.stderr && child.stderr.on('data', (data) => {
// bail if this is a line from xlib or libudev
if (isXlibOrLibudevRe.test(data.toString())) {
const str = data.toString()

// bail if this is warning line garbage
if (isXlibOrLibudevRe.test(str) || isHighSierraWarningRe.test(str)) {
return
}

Expand All @@ -114,7 +112,8 @@ module.exports = {
}

const userFriendlySpawn = () => {
return spawn().catch(throwFormErrorText(errors.unexpected))
return spawn()
.catch(throwFormErrorText(errors.unexpected))
}

if (needsXvfb) {
Expand Down
52 changes: 49 additions & 3 deletions cli/lib/util.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const _ = require('lodash')
const R = require('ramda')
const os = require('os')
const tty = require('tty')
const path = require('path')
const isCi = require('is-ci')
const getos = require('getos')
Expand Down Expand Up @@ -67,10 +68,55 @@ const util = {
return isCi
},

getEnvOverrides () {
return _
.chain({})
.extend(util.getEnvColors())
.extend(util.getForceTty())
.omitBy(_.isUndefined) // remove undefined values
.mapValues((value) => { // stringify to 1 or 0
return value ? '1' : '0'
})
.value()
},

getForceTty () {
return {
FORCE_STDIN_TTY: util.isTty(process.stdin.fd),
FORCE_STDOUT_TTY: util.isTty(process.stdout.fd),
FORCE_STDERR_TTY: util.isTty(process.stderr.fd),
}
},

getEnvColors () {
const sc = util.supportsColor()

return {
FORCE_COLOR: sc,
DEBUG_COLORS: sc,
MOCHA_COLORS: sc ? true : undefined,
}
},

isTty (fd) {
return tty.isatty(fd)
},

supportsColor () {
// we only care about stderr supporting color
// since thats what our DEBUG logs use
return Boolean(supportsColor.stderr)
// if we've been explictly told not to support
// color then turn this off
if (process.env.NO_COLOR) {
return false
}

// https://github.com/cypress-io/cypress/issues/1747
// always return true in CI providers
if (process.env.CI) {
return true
}

// ensure that both stdout and stderr support color
return Boolean(supportsColor.stdout) && Boolean(supportsColor.stderr)
},

cwd () {
Expand Down

0 comments on commit d154739

Please sign in to comment.