mirror of
https://github.com/openstf/stf
synced 2025-10-05 10:39:25 +02:00
Refactor doctor to be more resilient to unexpected errors, which made our life even harder especially on Ubuntu where the RethinkDB version contains more things in it.
This commit is contained in:
parent
0e751ca3d7
commit
6f1025e8ff
2 changed files with 176 additions and 190 deletions
|
@ -7,5 +7,180 @@ module.exports.builder = function(yargs) {
|
|||
}
|
||||
|
||||
module.exports.handler = function() {
|
||||
return require('../../util/doctor').run()
|
||||
var cp = require('child_process')
|
||||
var os = require('os')
|
||||
var util = require('util')
|
||||
|
||||
var semver = require('semver')
|
||||
var Promise = require('bluebird')
|
||||
var zmq = require('zmq')
|
||||
|
||||
var pkg = require('../../../package')
|
||||
var log = require('../../util/logger').createLogger('cli:doctor')
|
||||
|
||||
function CheckError() {
|
||||
Error.captureStackTrace(this, this.constructor)
|
||||
this.name = 'CheckError'
|
||||
this.message = util.format.apply(util, arguments)
|
||||
}
|
||||
|
||||
util.inherits(CheckError, Error)
|
||||
|
||||
function call(command, args, options) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var proc = cp.spawn(command, args, options)
|
||||
var stdout = []
|
||||
|
||||
proc.stdout.on('readable', function() {
|
||||
var chunk
|
||||
while ((chunk = proc.stdout.read())) {
|
||||
stdout.push(chunk)
|
||||
}
|
||||
})
|
||||
|
||||
proc.on('error', reject)
|
||||
|
||||
proc.on('exit', function(code, signal) {
|
||||
if (signal) {
|
||||
reject(new CheckError('Exited with signal %s', signal))
|
||||
}
|
||||
else if (code === 0) {
|
||||
resolve(Buffer.concat(stdout).toString())
|
||||
}
|
||||
else {
|
||||
reject(new CheckError('Exited with status %s', code))
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function check(label, fn) {
|
||||
return Promise.try(function() {
|
||||
function Check() {
|
||||
}
|
||||
|
||||
Check.prototype.call = function(command, args, options) {
|
||||
return call(command, args, options).catch(function(err) {
|
||||
if (err.code === 'ENOENT') {
|
||||
throw new CheckError(
|
||||
'%s is not installed (`%s` is missing)'
|
||||
, label
|
||||
, command
|
||||
)
|
||||
}
|
||||
|
||||
throw err
|
||||
})
|
||||
}
|
||||
|
||||
Check.prototype.extract = function(what, re) {
|
||||
return function(input) {
|
||||
return Promise.try(function() {
|
||||
var match = re.exec(input)
|
||||
if (!match) {
|
||||
throw new CheckError(util.format('%s %s cannot be detected', label, what))
|
||||
}
|
||||
return match[1]
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Check.prototype.version = function(wantedVersion) {
|
||||
return function(currentVersion) {
|
||||
return Promise.try(function() {
|
||||
log.info('Using %s %s', label, currentVersion)
|
||||
var sanitizedVersion = currentVersion.replace(/~.*/, '')
|
||||
return semver.satisfies(sanitizedVersion, wantedVersion)
|
||||
})
|
||||
.then(function(satisfied) {
|
||||
if (!satisfied) {
|
||||
throw new CheckError(
|
||||
'%s is currently %s but needs to be %s'
|
||||
, label
|
||||
, currentVersion
|
||||
, wantedVersion
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return fn(new Check())
|
||||
.catch(CheckError, function(err) {
|
||||
log.error(err.message)
|
||||
})
|
||||
.catch(function(err) {
|
||||
log.error('Unexpected error checking %s: %s', label, err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function checkOSArch() {
|
||||
log.info('OS Arch: %s', os.arch())
|
||||
}
|
||||
|
||||
function checkOSPlatform() {
|
||||
log.info('OS Platform: %s', os.platform())
|
||||
if (os.platform() === 'win32') {
|
||||
log.warn('STF has never been tested on Windows. Contributions are welcome!')
|
||||
}
|
||||
}
|
||||
|
||||
function checkOSRelease() {
|
||||
log.info('OS Platform: %s', os.release())
|
||||
}
|
||||
|
||||
function checkNodeVersion() {
|
||||
log.info('Using Node %s', process.versions.node)
|
||||
}
|
||||
|
||||
function checkLocalRethinkDBVersion() {
|
||||
return check('RethinkDB', function(checker) {
|
||||
return checker.call('rethinkdb', ['--version'])
|
||||
.then(checker.extract('version', /rethinkdb ([^\s]+)/))
|
||||
.then(checker.version(pkg.externalDependencies.rethinkdb))
|
||||
})
|
||||
}
|
||||
|
||||
function checkGraphicsMagick() {
|
||||
return check('GraphicsMagick', function(checker) {
|
||||
return checker.call('gm', ['-version'])
|
||||
.then(checker.extract('version', /GraphicsMagick ([^\s]+)/))
|
||||
.then(checker.version(pkg.externalDependencies.gm))
|
||||
})
|
||||
}
|
||||
|
||||
function checkZeroMQ() {
|
||||
return check('ZeroMQ', function(checker) {
|
||||
return checker.version(pkg.externalDependencies.zeromq)(zmq.version)
|
||||
})
|
||||
}
|
||||
|
||||
function checkProtoBuf() {
|
||||
return check('ProtoBuf', function(checker) {
|
||||
return checker.call('protoc', ['--version'])
|
||||
.then(checker.extract('version', /libprotoc ([^\s]+)/))
|
||||
.then(checker.version(pkg.externalDependencies.protobuf))
|
||||
})
|
||||
}
|
||||
|
||||
function checkADB() {
|
||||
return check('ADB', function(checker) {
|
||||
return checker.call('adb', ['version'])
|
||||
.then(checker.extract('version', /Android Debug Bridge version ([^\s]+)/))
|
||||
.then(checker.version(pkg.externalDependencies.adb))
|
||||
})
|
||||
}
|
||||
|
||||
return Promise.all([
|
||||
checkOSArch()
|
||||
, checkOSPlatform()
|
||||
, checkOSRelease()
|
||||
, checkNodeVersion()
|
||||
, checkLocalRethinkDBVersion()
|
||||
, checkGraphicsMagick()
|
||||
, checkZeroMQ()
|
||||
, checkProtoBuf()
|
||||
, checkADB()
|
||||
])
|
||||
}
|
||||
|
|
|
@ -1,189 +0,0 @@
|
|||
var os = require('os')
|
||||
var semver = require('semver')
|
||||
var childProcess = require('child_process')
|
||||
var rethinkdbPkg = require('rethinkdb/package')
|
||||
var zmq = require('zmq')
|
||||
|
||||
var pkg = require('../../package')
|
||||
var log = require('./logger').createLogger('util:doctor')
|
||||
|
||||
var doctor = module.exports = Object.create(null)
|
||||
|
||||
function unsupportedVersion(desc, ver, range, callback) {
|
||||
if (!semver.satisfies(ver, range)) {
|
||||
log.error(
|
||||
'Current %s version is not supported, it has to be %s'
|
||||
, desc
|
||||
, range
|
||||
)
|
||||
if (callback) {
|
||||
return callback()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function execHasErrors(error, stderr) {
|
||||
if (error) {
|
||||
if (error.code === 'ENOENT') {
|
||||
log.warn('Executable was not found')
|
||||
}
|
||||
else {
|
||||
log.error(error)
|
||||
}
|
||||
return true
|
||||
}
|
||||
if (stderr) {
|
||||
log.error('There was an error with: %s', stderr)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function execCommand(command, param, desc, match, callback) {
|
||||
childProcess.execFile(command, [param],
|
||||
function(error, stdout, stderr) {
|
||||
if (!execHasErrors(error, stderr)) {
|
||||
if (stdout) {
|
||||
var result = stdout.replace(match, '$1')
|
||||
if (result) {
|
||||
log.info('%s %s', desc, result)
|
||||
if (callback) {
|
||||
return callback(result)
|
||||
}
|
||||
}
|
||||
else {
|
||||
log.error('There was an error with: %s', stdout)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
doctor.checkOSArch = function() {
|
||||
log.info('OS Arch: %s', os.arch())
|
||||
}
|
||||
|
||||
doctor.checkOSPlatform = function() {
|
||||
log.info('OS Platform: %s', os.platform())
|
||||
if (os.platform() === 'win32') {
|
||||
log.warn('STF has never been tested on Windows. Contributions are welcome!')
|
||||
}
|
||||
}
|
||||
|
||||
doctor.checkOSRelease = function() {
|
||||
log.info('OS Platform: %s', os.release())
|
||||
}
|
||||
|
||||
doctor.checkNodeVersion = function() {
|
||||
log.info('Using Node %s', process.versions.node)
|
||||
if (pkg.engineStrict) {
|
||||
unsupportedVersion('Node', process.versions.node, pkg.engines.node)
|
||||
}
|
||||
}
|
||||
|
||||
doctor.checkRethinkDBClient = function() {
|
||||
log.info('Using RethinkDB client %s', rethinkdbPkg.version)
|
||||
}
|
||||
|
||||
doctor.checkLocalRethinkDBServer = function() {
|
||||
execCommand(
|
||||
'rethinkdb'
|
||||
, '--version'
|
||||
, 'Local RethinkDB server'
|
||||
, /rethinkdb (.*?) \(.*\)\n?/gm
|
||||
, function(ver) {
|
||||
unsupportedVersion(
|
||||
'Local RethinkDB server'
|
||||
, ver
|
||||
, pkg.externalDependencies.rethinkdb
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
doctor.checkGraphicsMagick = function() {
|
||||
execCommand(
|
||||
'gm'
|
||||
, '-version'
|
||||
, 'GraphicsMagick'
|
||||
, /GraphicsMagick ((.|\n)*?) (.|\n)*/g
|
||||
, function(ver) {
|
||||
unsupportedVersion('GraphicsMagick', ver, pkg.externalDependencies.gm)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
doctor.checkZeroMQ = function() {
|
||||
log.info('Using ZeroMQ %s', zmq.version)
|
||||
|
||||
unsupportedVersion('ZeroMQ', zmq.version, pkg.externalDependencies.zeromq)
|
||||
}
|
||||
|
||||
doctor.checkProtoBuf = function() {
|
||||
execCommand(
|
||||
'protoc'
|
||||
, '--version'
|
||||
, 'ProtoBuf'
|
||||
, /^libprotoc (.*)\n$/g
|
||||
, function(ver) {
|
||||
unsupportedVersion(
|
||||
'ProtoBuf'
|
||||
, ver
|
||||
, pkg.externalDependencies.protobuf
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
doctor.checkADB = function() {
|
||||
execCommand(
|
||||
'adb'
|
||||
, 'version'
|
||||
, 'Local ADB'
|
||||
, /Android Debug Bridge version (\d+\.\d+\.\d+)(\n.*)?/g
|
||||
, function(ver) {
|
||||
unsupportedVersion('AD', ver, pkg.externalDependencies.adb)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
doctor.run = function() {
|
||||
// Check OS architecture
|
||||
doctor.checkOSArch()
|
||||
|
||||
// Check OS platform
|
||||
doctor.checkOSPlatform()
|
||||
|
||||
// Check OS release
|
||||
doctor.checkOSRelease()
|
||||
|
||||
// Check node version
|
||||
doctor.checkNodeVersion()
|
||||
|
||||
// Check rethinkdb client
|
||||
doctor.checkRethinkDBClient()
|
||||
|
||||
// Check local rethinkdb server
|
||||
doctor.checkLocalRethinkDBServer()
|
||||
|
||||
// Check graphicsmagick
|
||||
doctor.checkGraphicsMagick()
|
||||
|
||||
// Check zeromq
|
||||
doctor.checkZeroMQ()
|
||||
|
||||
// Check protobuf
|
||||
doctor.checkProtoBuf()
|
||||
|
||||
// Check adb
|
||||
doctor.checkADB()
|
||||
|
||||
// TODO:
|
||||
// Check yasm
|
||||
// Check pkg-config
|
||||
// Check python2
|
||||
// Exit on errors
|
||||
// Run on stf local
|
||||
|
||||
// Only for stf local:
|
||||
// Check if rethinkdb is running
|
||||
// Check if adb server is running
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue