Skip to content

Instantly share code, notes, and snippets.

@pmuellr
Last active May 6, 2016 12:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save pmuellr/5b6bbc50e19ed6ae9809a038a998c470 to your computer and use it in GitHub Desktop.
Save pmuellr/5b6bbc50e19ed6ae9809a038a998c470 to your computer and use it in GitHub Desktop.
Generate a diagram of package deps for running N|Solid instances, in graphviz dot notation, using the N|Solid agent `package_info` command. For more info on N|Solid, head over to https://nodesource.com/products/nsolid
#!/usr/bin/env node
// Generate a graphviz (graphviz.org) .dot file for the package relationships
// of the currently running N|Solid instances, using the N|Solid 1.3
// package_info command.
'use strict'
var fs = require('fs')
var path = require('path')
var child_process = require('child_process')
nsolidAgent('info', function (err, infos) {
if (err) {
console.log('error connecting to N|Solid agents:', err.message)
return
}
if (infos.length == 0) {
console.log('There are no N|Solid agents running at this time')
return
}
console.log('To convert the generated graphviz .dot files to PDF, use the command:')
console.log('')
console.log(' dot -Tpdf -O <file name of .dot file>')
console.log('')
infos.forEach(function (info) {
var appId = {
app: info.app,
id: info.id
}
getPackageInfo(appId)
})
})
function getPackageInfo (appId) {
var app = appId.app
var id = appId.id
nsolidAgent('package_info', app, id, function (err, packageInfo) {
if (err) throw err
processPackageInfo(app, id, packageInfo)
})
}
function processPackageInfo (app, id, packageInfo) {
if (!packageInfo.packages) throw new Error('expecting packages property')
// get the package directories
var pkgDirs = packageInfo.packages.map(function (pkg) { return pkg.path })
// create a map of package dir : package, and name/version counts
var pkgMap = {}
var pkgCount = {}
packageInfo.packages.forEach(function (pkg) {
pkgMap[pkg.path] = pkg
const nameVersion = pkg.name + '@' + pkg.version
if (pkgCount[nameVersion] == null) {
pkgCount[nameVersion] = 1
} else {
pkgCount[nameVersion]++
}
})
// turn all the dependencies into refs to their packages
packageInfo.packages.forEach(function (pkg) {
pkg.dependencies = pkg.dependencies.map(function (dep) {
var depPath = path.resolve(pkg.path, dep)
return pkgMap[depPath]
})
})
// console.log(app + ' - ' + id)
// console.log('')
var oName = app + '-' + id + '.dot'
console.log('creating ' + oName)
var oStream = fs.createWriteStream(oName)
oStream.write('digraph packages {\n')
oStream.write('node [style=filled];\n')
pkgDirs.forEach(function (pkgDir) {
var pkg = pkgMap[pkgDir]
var pkgNode = pkg.name + '\\n' + pkg.version
var count = pkgCount[pkg.name + '@' + pkg.version]
if (count > 1) {
oStream.write('"' + getNodeName(pkg) + '" [color="#FFA0A0"];\n')
}
pkg.dependencies.forEach(function (dep) {
oStream.write('"' + getNodeName(pkg) + '" -> "' + getNodeName(dep) + '";\n')
})
})
oStream.write('}\n')
function getNodeName(pkg) {
var name = pkg.name.replace(/-/g, '-\\n') + '\\n' + pkg.version
var count = pkgCount[pkg.name + '@' + pkg.version]
if (count === 1) return name
return name + '\\n' + count + ' copies'
}
}
function uniquePackageVersions (pkgs) {
var result = []
var found = {}
pkgs.forEach(function (pkg) {
var pkgVersion = pkg.name + '@' + pkg.version
if (found[pkgVersion]) return
found[pkgVersion] = true
result.push({
name: pkg.name,
version: pkg.version
})
})
return result
}
function nsolidAgent (command, app, id, cb) {
if ((typeof app === 'function') && !id && !cb) {
cb = app
app = null
id = null
}
if ((typeof id === 'function') && !cb) {
cb = id
id = null
}
var options = []
if (app) options.push('--app ' + app)
if (id) options.push('--id ' + id)
options = options.join(' ')
if (options !== '') options = ' ' + options + ' '
command = 'nsolid-cli' + options + ' ' + command
var execOpts = {
maxBuffer: 20 * 1000 * 1000
}
child_process.exec(command, execOpts, done)
debugLog('running: ' + command)
function done (err, stdout, stderr) {
debugLog('ran: ' + command)
if (stderr) debugLog('stderr: ' + stderr)
if (err) {
debugLog('err: ' + err)
return cb(err)
}
var result = []
var lines = stdout.split('\n')
for (var i = 0; i < lines.length; i++) {
var line = lines[i]
if (line === '') continue
try {
line = JSON.parse(line)
} catch (err) {
line = JSON.stringify({err: 'invalid JSON'})
}
if (app && id) {
result.push(line)
} else {
result.push(line.reply)
}
}
if (app && id) {
cb(null, result[0])
} else {
cb(null, result)
}
}
}
function debugLog (message) {
// console.error(message)
}
@pmuellr
Copy link
Author

pmuellr commented May 4, 2016

Some sample output from running dillinger: https://github.com/joemccann/dillinger

dillinger-4f5dea910cd8451ed430f08184f0640e1dcf8477 dot

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment