0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-01-06 22:40:14 -05:00

Install App Dependencies

- Spawns an npm install command from the App root
- Has some special OS checks for windows command spawning
This commit is contained in:
Jacob Gable 2014-02-02 00:07:39 -06:00
parent 2beba7f1d7
commit e3affff713
3 changed files with 116 additions and 18 deletions

View file

@ -0,0 +1,52 @@
var _ = require('lodash'),
fs = require('fs'),
path = require('path'),
when = require('when'),
spawn = require('child_process').spawn,
win32 = process.platform === 'win32';
function AppDependencies(appPath) {
this.appPath = appPath;
}
AppDependencies.prototype.install = function installAppDependencies() {
var def = when.defer(),
spawnOpts;
fs.exists(path.join(this.appPath, 'package.json'), function (exists) {
if (!exists) {
// Nothing to do, resolve right away?
def.resolve();
} else {
// Run npm install in the app directory
spawnOpts = {
cwd: this.appPath
};
this.spawnCommand('npm', ['install', '--production'], spawnOpts)
.on('error', def.reject)
.on('exit', function (err) {
if (err) {
def.reject(err);
}
def.resolve();
});
}
}.bind(this));
return def.promise;
};
// Normalize a command across OS and spawn it; taken from yeoman/generator
AppDependencies.prototype.spawnCommand = function (command, args, opt) {
var winCommand = win32 ? 'cmd' : command,
winArgs = win32 ? ['/c'].concat(command, args) : args;
opt = opt || {};
return spawn(winCommand, winArgs, _.defaults({ stdio: 'inherit' }, opt));
};
module.exports = AppDependencies;

View file

@ -5,14 +5,20 @@ var path = require('path'),
appProxy = require('./proxy'),
config = require('../config'),
AppSandbox = require('./sandbox'),
AppDependencies = require('./dependencies'),
loader;
// Get the full path to an app by name
function getAppAbsolutePath(name) {
return path.join(config().paths.appPath, name);
}
// Get a relative path to the given apps root, defaults
// to be relative to __dirname
function getAppRelativePath(name, relativeTo) {
relativeTo = relativeTo || __dirname;
return path.relative(relativeTo, path.join(config().paths.appPath, name));
return path.relative(relativeTo, getAppAbsolutePath(name));
}
// Load apps through a psuedo sandbox
@ -41,17 +47,22 @@ function getAppByName(name) {
loader = {
// Load a app and return the instantiated app
installAppByName: function (name) {
var app = getAppByName(name);
// Install the apps dependendencies first
var deps = new AppDependencies(getAppAbsolutePath(name));
return deps.install().then(function () {
var app = getAppByName(name);
// Check for an install() method on the app.
if (!_.isFunction(app.install)) {
return when.reject(new Error("Error loading app named " + name + "; no install() method defined."));
}
// Check for an install() method on the app.
if (!_.isFunction(app.install)) {
return when.reject(new Error("Error loading app named " + name + "; no install() method defined."));
}
// Wrapping the install() with a when because it's possible
// to not return a promise from it.
return when(app.install(appProxy)).then(function () {
return when.resolve(app);
// Run the app.install() method
// Wrapping the install() with a when because it's possible
// to not return a promise from it.
return when(app.install(appProxy)).then(function () {
return when.resolve(app);
});
});
},

View file

@ -1,15 +1,17 @@
/*globals describe, beforeEach, afterEach, before, it*/
var fs = require('fs'),
path = require('path'),
should = require('should'),
sinon = require('sinon'),
_ = require('lodash'),
helpers = require('../../server/helpers'),
filters = require('../../server/filters'),
var fs = require('fs'),
path = require('path'),
EventEmitter = require('events').EventEmitter,
should = require('should'),
sinon = require('sinon'),
_ = require('lodash'),
helpers = require('../../server/helpers'),
filters = require('../../server/filters'),
// Stuff we are testing
appProxy = require('../../server/apps/proxy'),
AppSandbox = require('../../server/apps/sandbox');
AppSandbox = require('../../server/apps/sandbox'),
AppDependencies = require('../../server/apps/dependencies');
describe('Apps', function () {
@ -154,4 +156,37 @@ describe('Apps', function () {
loadApp.should.throw(/^Unsafe App require[\w\W]*example$/);
});
});
describe('Dependencies', function () {
it('can install by package.json', function (done) {
var deps = new AppDependencies(process.cwd()),
fakeEmitter = new EventEmitter();
deps.spawnCommand = sandbox.stub().returns(fakeEmitter);
deps.install().then(function () {
deps.spawnCommand.calledWith('npm').should.equal(true);
done();
}).otherwise(done);
_.delay(function () {
fakeEmitter.emit('exit');
}, 30);
});
it('does not install when no package.json', function (done) {
var deps = new AppDependencies(__dirname),
fakeEmitter = new EventEmitter();
deps.spawnCommand = sandbox.stub().returns(fakeEmitter);
deps.install().then(function () {
deps.spawnCommand.called.should.equal(false);
done();
}).otherwise(done);
_.defer(function () {
fakeEmitter.emit('exit');
});
});
});
});