Last active
May 6, 2016 12:00
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Some sample output from running dillinger: https://github.com/joemccann/dillinger