Skip to content

Commit

Permalink
Merge branch 'master' into instrument-copy-full
Browse files Browse the repository at this point in the history
  • Loading branch information
coreyfarrell committed Apr 7, 2019
2 parents b10aaee + e597c46 commit a12d0d6
Show file tree
Hide file tree
Showing 17 changed files with 417 additions and 108 deletions.
40 changes: 16 additions & 24 deletions bin/nyc.js
Expand Up @@ -65,35 +65,27 @@ if ([
), function (done) {
var mainChildExitCode = process.exitCode

if (argv.showProcessTree || argv.buildProcessTree) {
nyc.writeProcessIndex()
}

if (argv.checkCoverage) {
checkCoverage(argv)
nyc.checkCoverage({
lines: argv.lines,
functions: argv.functions,
branches: argv.branches,
statements: argv.statements
}, argv['per-file'])
process.exitCode = process.exitCode || mainChildExitCode
if (!argv.silent) report(argv)
return done()
} else {
if (!argv.silent) report(argv)
return done()
}

if (!argv.silent) {
nyc.report()
}

return done()
})
} else {
// I don't have a clue what you're doing.
yargs.showHelp()
}

function report (argv) {
process.env.NYC_CWD = process.cwd()

var nyc = new NYC(argv)
nyc.report()
}

function checkCoverage (argv, cb) {
process.env.NYC_CWD = process.cwd()

;(new NYC(argv)).checkCoverage({
lines: argv.lines,
functions: argv.functions,
branches: argv.branches,
statements: argv.statements
}, argv['per-file'])
}
11 changes: 7 additions & 4 deletions bin/wrap.js
@@ -1,17 +1,20 @@
var sw = require('spawn-wrap')
var NYC = require('../index.js')

var parentPid = process.env.NYC_PARENT_PID || '0'
process.env.NYC_PARENT_PID = process.pid

var config = {}
if (process.env.NYC_CONFIG) config = JSON.parse(process.env.NYC_CONFIG)
config.isChildProcess = true

config._processInfo = {
ppid: parentPid,
pid: process.pid,
ppid: process.ppid,
parent: process.env.NYC_PROCESS_ID || null,
root: process.env.NYC_ROOT_ID
}
if (process.env.NYC_PROCESSINFO_EXTERNAL_ID) {
config._processInfo.externalId = process.env.NYC_PROCESSINFO_EXTERNAL_ID
delete process.env.NYC_PROCESSINFO_EXTERNAL_ID
}

;(new NYC(config)).wrap()

Expand Down
109 changes: 95 additions & 14 deletions index.js
Expand Up @@ -2,7 +2,6 @@

/* global __coverage__ */

const arrify = require('arrify')
const cachingTransform = require('caching-transform')
const cpFile = require('cp-file')
const findCacheDir = require('find-cache-dir')
Expand Down Expand Up @@ -46,12 +45,12 @@ function NYC (config) {
this._buildProcessTree = this._showProcessTree || config.buildProcessTree
this._eagerInstantiation = config.eager || false
this.cwd = config.cwd || process.cwd()
this.reporter = arrify(config.reporter || 'text')
this.reporter = [].concat(config.reporter || 'text')

this.cacheDirectory = (config.cacheDir && path.resolve(config.cacheDir)) || findCacheDir({ name: 'nyc', cwd: this.cwd })
this.cache = Boolean(this.cacheDirectory && config.cache)

this.extensions = arrify(config.extension)
this.extensions = [].concat(config.extension || [])
.concat('.js')
.map(ext => ext.toLowerCase())
.filter((item, pos, arr) => arr.indexOf(item) === pos)
Expand All @@ -70,7 +69,7 @@ function NYC (config) {
})

// require extensions can be provided as config in package.json.
this.require = arrify(config.require)
this.require = [].concat(config.require || [])

this.transforms = this.extensions.reduce((transforms, ext) => {
transforms[ext] = this._createTransform(ext)
Expand Down Expand Up @@ -317,6 +316,7 @@ NYC.prototype._wrapExit = function () {
}

NYC.prototype.wrap = function (bin) {
process.env.NYC_PROCESS_ID = this.processInfo.uuid
this._addRequireHooks()
this._wrapExit()
this._loadAdditionalModules()
Expand Down Expand Up @@ -346,7 +346,7 @@ NYC.prototype.writeCoverageFile = function () {
coverage = this.sourceMaps.remapCoverage(coverage)
}

var id = this.generateUniqueID()
var id = this.processInfo.uuid
var coverageFilename = path.resolve(this.tempDirectory(), id + '.json')

fs.writeFileSync(
Expand All @@ -360,6 +360,7 @@ NYC.prototype.writeCoverageFile = function () {
}

this.processInfo.coverageFilename = coverageFilename
this.processInfo.files = Object.keys(coverage)

fs.writeFileSync(
path.resolve(this.processInfoDirectory(), id + '.json'),
Expand Down Expand Up @@ -417,6 +418,80 @@ NYC.prototype.report = function () {
}
}

// XXX(@isaacs) Index generation should move to istanbul-lib-processinfo
NYC.prototype.writeProcessIndex = function () {
const dir = this.processInfoDirectory()
const pidToUid = new Map()
const infoByUid = new Map()
const eidToUid = new Map()
const infos = fs.readdirSync(dir).filter(f => f !== 'index.json').map(f => {
try {
const info = JSON.parse(fs.readFileSync(path.resolve(dir, f), 'utf-8'))
info.children = []
pidToUid.set(info.uuid, info.pid)
pidToUid.set(info.pid, info.uuid)
infoByUid.set(info.uuid, info)
if (info.externalId) {
eidToUid.set(info.externalId, info.uuid)
}
return info
} catch (er) {
return null
}
}).filter(Boolean)

// create all the parent-child links and write back the updated info
infos.forEach(info => {
if (info.parent) {
const parentInfo = infoByUid.get(info.parent)
if (parentInfo.children.indexOf(info.uuid) === -1) {
parentInfo.children.push(info.uuid)
}
}
})

// figure out which files were touched by each process.
const files = infos.reduce((files, info) => {
info.files.forEach(f => {
files[f] = files[f] || []
files[f].push(info.uuid)
})
return files
}, {})

// build the actual index!
const index = infos.reduce((index, info) => {
index.processes[info.uuid] = {}
index.processes[info.uuid].parent = info.parent
if (info.externalId) {
if (index.externalIds[info.externalId]) {
throw new Error(`External ID ${info.externalId} used by multiple processes`)
}
index.processes[info.uuid].externalId = info.externalId
index.externalIds[info.externalId] = {
root: info.uuid,
children: info.children
}
}
index.processes[info.uuid].children = Array.from(info.children)
return index
}, { processes: {}, files: files, externalIds: {} })

// flatten the descendant sets of all the externalId procs
Object.keys(index.externalIds).forEach(eid => {
const { children } = index.externalIds[eid]
// push the next generation onto the list so we accumulate them all
for (let i = 0; i < children.length; i++) {
const nextGen = index.processes[children[i]].children
if (nextGen && nextGen.length) {
children.push(...nextGen.filter(uuid => children.indexOf(uuid) === -1))
}
}
})

fs.writeFileSync(path.resolve(dir, 'index.json'), JSON.stringify(index))
}

NYC.prototype.showProcessTree = function () {
var processTree = ProcessInfo.buildProcessTree(this._loadProcessInfos())

Expand Down Expand Up @@ -453,19 +528,25 @@ NYC.prototype._checkCoverage = function (summary, thresholds, file) {
}

NYC.prototype._loadProcessInfos = function () {
var _this = this
var files = fs.readdirSync(this.processInfoDirectory())

return files.map(function (f) {
return fs.readdirSync(this.processInfoDirectory()).map(f => {
let data
try {
return new ProcessInfo(JSON.parse(fs.readFileSync(
path.resolve(_this.processInfoDirectory(), f),
data = JSON.parse(fs.readFileSync(
path.resolve(this.processInfoDirectory(), f),
'utf-8'
)))
))
} catch (e) { // handle corrupt JSON output.
return {}
return null
}
})
if (f !== 'index.json') {
data.nodes = []
data = new ProcessInfo(data)
}
return { file: path.basename(f, '.json'), data: data }
}).filter(Boolean).reduce((infos, info) => {
infos[info.file] = info.data
return infos
}, {})
}

NYC.prototype.eachReport = function (filenames, iterator, baseDirectory) {
Expand Down
6 changes: 6 additions & 0 deletions lib/commands/check-coverage.js
Expand Up @@ -13,6 +13,12 @@ exports.builder = function (yargs) {
describe: 'a list of specific files and directories that should be excluded from coverage, glob patterns are supported, node_modules is always excluded',
global: false
})
.option('exclude-node-modules', {
default: true,
type: 'boolean',
describe: 'whether or not to exclude all node_module folders (i.e. **/node_modules/**) by default',
global: false
})
.option('exclude-after-remap', {
default: true,
type: 'boolean',
Expand Down
22 changes: 7 additions & 15 deletions lib/commands/instrument.js
Expand Up @@ -59,6 +59,12 @@ exports.builder = function (yargs) {
default: testExclude.defaultExclude,
describe: 'a list of specific files and directories that should not be instrumented, glob patterns are supported'
})
.option('exclude-node-modules', {
default: true,
type: 'boolean',
describe: 'whether or not to exclude all node_module folders (i.e. **/node_modules/**) by default',
global: false
})
.option('es-modules', {
default: true,
type: 'boolean',
Expand Down Expand Up @@ -105,21 +111,7 @@ exports.handler = function (argv) {
? './lib/instrumenters/istanbul'
: './lib/instrumenters/noop'

const nyc = new NYC({
instrumenter: argv.instrumenter,
sourceMap: argv.sourceMap,
produceSourceMap: argv.produceSourceMap,
extension: argv.extension,
require: argv.require,
cwd: argv.cwd,
compact: argv.compact,
preserveComments: argv.preserveComments,
include: argv.include,
exclude: argv.exclude,
esModules: argv.esModules,
completeCopy: argv.completeCopy,
exitOnError: argv.exitOnError
})
const nyc = new NYC(argv)

nyc.instrumentAllFiles(argv.input, argv.output, err => {
if (err) {
Expand Down
6 changes: 6 additions & 0 deletions lib/commands/report.js
Expand Up @@ -30,6 +30,12 @@ exports.builder = function (yargs) {
describe: 'a list of specific files and directories that should be excluded from coverage, glob patterns are supported, node_modules is always excluded',
global: false
})
.option('exclude-node-modules', {
default: true,
type: 'boolean',
describe: 'whether or not to exclude all node_module folders (i.e. **/node_modules/**) by default',
global: false
})
.option('exclude-after-remap', {
default: true,
type: 'boolean',
Expand Down
9 changes: 4 additions & 5 deletions lib/config-util.js
@@ -1,6 +1,5 @@
'use strict'

const arrify = require('arrify')
const fs = require('fs')
const path = require('path')
const findUp = require('find-up')
Expand Down Expand Up @@ -37,10 +36,10 @@ Config.loadConfig = function (argv, cwd) {
}
}

if (config.require) config.require = arrify(config.require)
if (config.extension) config.extension = arrify(config.extension)
if (config.exclude) config.exclude = arrify(config.exclude)
if (config.include) config.include = arrify(config.include)
if (config.require) config.require = [].concat(config.require)
if (config.extension) config.extension = [].concat(config.extension)
if (config.exclude) config.exclude = [].concat(config.exclude)
if (config.include) config.include = [].concat(config.include)

return config
}
Expand Down

0 comments on commit a12d0d6

Please sign in to comment.