Skip to content

Commit

Permalink
Basic functionality, proof of concept.
Browse files Browse the repository at this point in the history
  • Loading branch information
tfe committed Apr 6, 2011
1 parent bc4e94a commit 624601f
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 3 deletions.
94 changes: 94 additions & 0 deletions bin/detect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
#!/usr/bin/env node

var forAllFiles = require('../lib/tree-walk.js').forAllFiles,
npm = require('npm'),
util = require('util'),
path = require('path'),
fs = require('fs'),
exec = require('child_process').exec;

// recursively scan directory, build up array of requires
var dir = '.',
resolvedDir = path.resolve(dir),
packages = [], // array of all candidate packages found
npmPackages = []; // array of all packages that exist in the npm registry

util.log('Scanning directory "' + resolvedDir + '"... ')

forAllFiles(dir,
function (file, next) {
processFile(file);
next();
},

function (err) {
if (err) throw err;

util.log("Finished scanning, checking " + packages.length + " packages against npm registry...");

for (i=0; i < packages.length; i++) {
var packageName = packages[i];
checkRegistry(packageName);
}
}
)

function processFile(file) {

// exclude non-js files
if (file.substr(-3,3) !== '.js') {
return false;
}

// exclude hidden files and directories
if (file.search(/\/\..+/) > 0) {
return false;
}

// build array of packages required in this file
fs.readFile(file, 'utf8', function (err, data) {
if (err) throw err;

var requires = data.match(/require\(['"][a-z-_\.]*['"]\)/gi);
for (i=0; i < requires.length; i++) {
var name = requires[i].match(/['"]([a-z-_\.]*)['"]/)[1];
if (packages.indexOf(name) < 0) { // don't duplicate
packages.push(name);
}
}
});

util.log(' ' + file);
}

function checkRegistry(name) {

// Ideally, we'd accomplish the below by using npm programmatically, but instead we're just
// going to shell out and run npm because even when using npm programmatically, there's
// apparently no way to stop it spewing output all over stdout/stderr.

exec('npm search ' + name, function (err, stdout, stderr) {
if (err) throw err;

util.log(' ' + name);

// check for npm problems
if (stderr.search(/npm not ok/) > 0) {
throw "npm error, check your npm installation"
}

// see if any lines contain name@version as the first token
var cleanLines = [];
var lines = stdout.split("\n");

for (i=0; i < lines.length; i++) {
var line = lines[i];
var nameParts = line.split(' ')[0].split('@');
if (nameParts[0] === name && nameParts.length === 2) {
util.log(' ' + 'found');
npmPackages.push(name);
break;
}
}
});
}
11 changes: 8 additions & 3 deletions lib/tree_walk.js → lib/tree-walk.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
// Originally by Jack Palevich:
// http://grammerjack.blogspot.com/2010/12/asynchronous-directory-tree-walk-in.html

// Adapted for CommonJS by Todd Eichel ([email protected])

// asynchronous tree walk
// root - root path
// fileCb - callback function (file, next) called for each file
Expand All @@ -14,7 +17,9 @@
// function (file, next) { sys.log(file); next(); },
// function (err) { sys.log("done: " + err); });

function forAllFiles(root, fileCb, doneCb) {
var fs = require('fs');

exports.forAllFiles = function (root, fileCb, doneCb) {
fs.readdir(root, function processDir(err, files) {
if (err) {
fileCb(err);
Expand All @@ -34,7 +39,7 @@ function forAllFiles(root, fileCb, doneCb) {
}
});
} else {
forAllFiles(file, fileCb, function(err) {
exports.forAllFiles(file, fileCb, function(err) {
if (err) {
doneCb(err);
} else {
Expand All @@ -49,4 +54,4 @@ function forAllFiles(root, fileCb, doneCb) {
}
}
});
}
};
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,8 @@
},
"engines": {
"node": "*"
},
"dependencies": {
"npm": "~0.3.18"
}
}

0 comments on commit 624601f

Please sign in to comment.