squash! ScriptFileStorage: root detection change

Yet another improvement of root folder detection. Now we consider a folder
as an application root iff it contains `package.json` file.
This commit is contained in:
Miroslav Bajtos 2013-07-11 10:13:49 +02:00
Родитель 5fa37e9a14
Коммит 1b343ecb42
2 изменённых файлов: 54 добавлений и 89 удалений

Просмотреть файл

@ -67,21 +67,32 @@ $class.findApplicationRoot = function(mainScriptFile, callback) {
};
/**
* For a given script file, find the root directory containing all application
* source files.
*
* Example:
* file = ~/work/app/bin/cli.js
* root = ~/work/app
*
* The algorithm:
*
* By default, we assume that the source file is in the root directory
* (~/work/app/bin in the example above).
*
* If this directory does not contain 'package.json' and the parent directory
* contains 'package.json', then we assume the parent directory is
* the application root (~/work/app in the example above).
*
* @param {string} file
* @param {function(Object, string)} callback
* @this {ScriptFileStorage}
*/
$class._findApplicationRootForRealFile = function(file, callback) {
var mainDir = path.dirname(file);
var candidates = [mainDir];
if (path.basename(mainDir) === 'bin') {
var parentDir = path.dirname(mainDir);
candidates.push(parentDir);
}
var parentDir = path.dirname(mainDir);
async.detect(
candidates,
[mainDir, parentDir],
this._isApplicationRoot.bind(this),
function(result) {
callback(null, result || mainDir);
@ -94,13 +105,7 @@ $class._findApplicationRootForRealFile = function(file, callback) {
* @param {function(boolean)} callback
*/
$class._isApplicationRoot = function(folder, callback) {
async.any(
['lib', 'node_modules', 'test'],
function(f, cb) {
fs.exists(path.join(folder, f), cb);
},
callback
);
fs.exists(path.join(folder, 'package.json'), callback);
};
/**

Просмотреть файл

@ -40,79 +40,37 @@ describe('ScriptFileStorage', function() {
});
});
it('finds application root for bin/app.js by checking lib/ folder', function(done) {
givenTempFiles('bin/', 'bin/app.js', 'lib/');
storage.findApplicationRoot(
path.join(TEMP_DIR, 'bin', 'app.js'),
expectRootToEqualTempDir.bind(this, done)
);
});
it('finds application root for subdir/app.js by checking package.json file in parent',
function(done) {
givenTempFiles('subdir/', 'subdir/app.js', 'package.json');
storage.findApplicationRoot(
path.join(TEMP_DIR, 'subdir', 'app.js'),
expectRootToEqual.bind(this, done, TEMP_DIR)
);
}
);
it('finds application root for bin/app.js by checking node_modules/ folder', function(done) {
givenTempFiles('bin/', 'bin/app.js', 'node_modules/');
storage.findApplicationRoot(
path.join(TEMP_DIR, 'bin', 'app.js'),
expectRootToEqualTempDir.bind(this, done)
);
});
it('finds application root for root/app.js with no package.json files around',
function(done) {
// If the parent directory of app.js does not contain package.json,
// it should not be considered as an application root.
givenTempFiles('root/', 'root/app.js');
storage.findApplicationRoot(
path.join(TEMP_DIR, 'root', 'app.js'),
expectRootToEqual.bind(this, done, path.join(TEMP_DIR, 'root'))
);
}
);
it('finds application root for nonbin/app.js', function(done) {
// If the argv1 file is not in the bin/ folder, then we must not consider
// parent folder as an application root.
// Since we are detecting also 'test' folder as an indicator of an app root,
// considering a parent folder may return a folder that is not an app root,
// but contains lots of other projects instead.
// Consider following structure:
// ~/work/debugged-app/app.js # no more files, no node_modules folder
// ~/work/test/playground.js # test folder for trying out things
// ~/work/project1
// ~/work/project2
// (etc.) # other projects - a lot of files
givenTempFiles('nonbin/', 'nonbin/app.js', 'node_modules/');
storage.findApplicationRoot(
path.join(TEMP_DIR, 'nonbin', 'app.js'),
function(err, root) {
if (err) throw err;
expect(root).to.equal(path.join(TEMP_DIR, 'nonbin'));
done();
}
);
});
it('finds application root for app.js by checking lib/ folder', function(done) {
givenTempFiles('app.js', 'lib/');
storage.findApplicationRoot(
path.join(TEMP_DIR, 'app.js'),
expectRootToEqualTempDir.bind(this, done)
);
});
it('finds application root for app.js by checking node_modules/ folder', function(done) {
givenTempFiles('app.js', 'node_modules/');
storage.findApplicationRoot(
path.join(TEMP_DIR, 'app.js'),
expectRootToEqualTempDir.bind(this, done)
);
});
it('finds all application files', function(done) {
var expectedFiles = givenTempFiles(
'bin/', 'bin/app.js',
'lib/', 'lib/module.js',
'toplevel.js'
);
storage.findAllApplicationScripts(
NON_APP_DIR,
path.join(TEMP_DIR, 'bin', 'app.js'),
function(err, files) {
if (err) throw err;
expect(files.map(relativeToTemp))
.to.have.members(expectedFiles.map(relativeToTemp));
done();
}
);
});
it('finds application root for root/app.js by checking package.json file in root/',
function(done) {
givenTempFiles('root/', 'root/app.js', 'root/package.json', 'package.json');
storage.findApplicationRoot(
path.join(TEMP_DIR, 'root', 'app.js'),
expectRootToEqual.bind(this, done, path.join(TEMP_DIR, 'root'))
);
}
);
it('finds also files in start directory', function(done) {
var expectedFiles = givenTempFiles(
@ -129,6 +87,8 @@ describe('ScriptFileStorage', function() {
'unrelated/file.js'
);
givenTempFiles('global/package.json', 'local/package.json');
// remove unrelated/file.js
expect(expectedFiles.pop()).to.match(/unrelated[\/\\]file.js$/);
@ -145,7 +105,7 @@ describe('ScriptFileStorage', function() {
});
it('removes duplicate entries from files found', function(done) {
var expectedFiles = givenTempFiles('app.js', 'node_modules/');
var expectedFiles = givenTempFiles('app.js');
storage.findAllApplicationScripts(
TEMP_DIR,
@ -164,9 +124,9 @@ describe('ScriptFileStorage', function() {
return path.relative(TEMP_DIR, p);
}
function expectRootToEqualTempDir(done, err, root) {
function expectRootToEqual(done, expected, err, root) {
if (err) throw err;
expect(root).to.equal(TEMP_DIR);
expect(root).to.equal(expected);
done();
}
@ -192,7 +152,7 @@ describe('ScriptFileStorage', function() {
function givenTempFiles() {
var files = [];
fs.mkdirSync(TEMP_DIR);
if (!fs.existsSync(TEMP_DIR)) fs.mkdirSync(TEMP_DIR);
Array.prototype.forEach.call(arguments, function(f) {
f = path.join(TEMP_DIR, globPathToNative(f));
if (isDir(f)) {