Cypress_TS/CyLukTs/lukan/node_modules/@cypress/xvfb/index.js
Lukáš Kaňka ea3e372146 údržba
2023-08-15 18:35:50 +02:00

222 lines
5.9 KiB
JavaScript

/* eslint-disable node/no-deprecated-api */
'use strict'
// our debug log messages
const debug = require('debug')('xvfb')
const once = require('lodash.once')
const fs = require('fs')
const path = require('path')
const spawn = require('child_process').spawn
fs.exists = fs.exists || path.exists
fs.existsSync = fs.existsSync || path.existsSync
function Xvfb(options) {
options = options || {}
this._display = options.displayNum ? `:${options.displayNum}` : null
this._reuse = options.reuse
this._timeout = options.timeout || options.timeOut || 2000
this._silent = options.silent
this._onStderrData = options.onStderrData || (() => {})
this._xvfb_args = options.xvfb_args || []
}
Xvfb.prototype = {
start(cb) {
let self = this
if (!self._process) {
let lockFile = self._lockFile()
self._setDisplayEnvVariable()
fs.exists(lockFile, function(exists) {
let didSpawnFail = false
try {
self._spawnProcess(exists, function(e) {
debug('XVFB spawn failed')
debug(e)
didSpawnFail = true
if (cb) cb(e)
})
} catch (e) {
debug('spawn process error')
debug(e)
return cb && cb(e)
}
let totalTime = 0
;(function checkIfStarted() {
debug('checking if started by looking for the lock file', lockFile)
fs.exists(lockFile, function(exists) {
if (didSpawnFail) {
// When spawn fails, the callback will immediately be called.
// So we don't have to check whether the lock file exists.
debug('while checking for lock file, saw that spawn failed')
return
}
if (exists) {
debug('lock file %s found after %d ms', lockFile, totalTime)
return cb && cb(null, self._process)
} else {
totalTime += 10
if (totalTime > self._timeout) {
debug(
'could not start XVFB after %d ms (timeout %d ms)',
totalTime,
self._timeout
)
const err = new Error('Could not start Xvfb.')
err.timedOut = true
return cb && cb(err)
} else {
setTimeout(checkIfStarted, 10)
}
}
})
})()
})
}
},
stop(cb) {
let self = this
if (self._process) {
self._killProcess()
self._restoreDisplayEnvVariable()
let lockFile = self._lockFile()
debug('lock file', lockFile)
let totalTime = 0
;(function checkIfStopped() {
fs.exists(lockFile, function(exists) {
if (!exists) {
debug('lock file %s not found when stopping', lockFile)
return cb && cb(null, self._process)
} else {
totalTime += 10
if (totalTime > self._timeout) {
debug('lock file %s is still there', lockFile)
debug(
'after waiting for %d ms (timeout %d ms)',
totalTime,
self._timeout
)
const err = new Error('Could not stop Xvfb.')
err.timedOut = true
return cb && cb(err)
} else {
setTimeout(checkIfStopped, 10)
}
}
})
})()
} else {
return cb && cb(null)
}
},
display() {
if (!this._display) {
let displayNum = 98
let lockFile
do {
displayNum++
lockFile = this._lockFile(displayNum)
} while (!this._reuse && fs.existsSync(lockFile))
this._display = `:${displayNum}`
}
return this._display
},
_setDisplayEnvVariable() {
this._oldDisplay = process.env.DISPLAY
process.env.DISPLAY = this.display()
debug('setting DISPLAY %s', process.env.DISPLAY)
},
_restoreDisplayEnvVariable() {
debug('restoring process.env.DISPLAY variable')
// https://github.com/cypress-io/xvfb/issues/1
// only reset truthy backed' up values
if (this._oldDisplay) {
process.env.DISPLAY = this._oldDisplay
} else {
// else delete the values to get back
// to undefined
delete process.env.DISPLAY
}
},
_spawnProcess(lockFileExists, onAsyncSpawnError) {
let self = this
const onError = once(onAsyncSpawnError)
let display = self.display()
if (lockFileExists) {
if (!self._reuse) {
throw new Error(
`Display ${display} is already in use and the "reuse" option is false.`
)
}
} else {
const stderr = []
const allArguments = [display].concat(self._xvfb_args)
debug('all Xvfb arguments', allArguments)
self._process = spawn('Xvfb', allArguments)
self._process.stderr.on('data', function(data) {
stderr.push(data.toString())
if (self._silent) {
return
}
self._onStderrData(data)
})
self._process.on('close', (code, signal) => {
if (code !== 0) {
const str = stderr.join('\n')
debug('xvfb closed with error code', code)
debug('after receiving signal %s', signal)
debug('and stderr output')
debug(str)
const err = new Error(str)
err.nonZeroExitCode = true
onError(err)
}
})
// Bind an error listener to prevent an error from crashing node.
self._process.once('error', function(e) {
debug('xvfb spawn process error')
debug(e)
onError(e)
})
}
},
_killProcess() {
this._process.kill()
this._process = null
},
_lockFile(displayNum) {
displayNum =
displayNum ||
this.display()
.toString()
.replace(/^:/, '')
const filename = `/tmp/.X${displayNum}-lock`
debug('lock filename %s', filename)
return filename
},
}
module.exports = Xvfb