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:
parent
2beba7f1d7
commit
e3affff713
3 changed files with 116 additions and 18 deletions
52
core/server/apps/dependencies.js
Normal file
52
core/server/apps/dependencies.js
Normal 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;
|
|
@ -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,6 +47,9 @@ function getAppByName(name) {
|
|||
loader = {
|
||||
// Load a app and return the instantiated app
|
||||
installAppByName: function (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.
|
||||
|
@ -48,11 +57,13 @@ loader = {
|
|||
return when.reject(new Error("Error loading app named " + name + "; no install() method defined."));
|
||||
}
|
||||
|
||||
// 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);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
// Activate a app and return it
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*globals describe, beforeEach, afterEach, before, it*/
|
||||
var fs = require('fs'),
|
||||
path = require('path'),
|
||||
EventEmitter = require('events').EventEmitter,
|
||||
should = require('should'),
|
||||
sinon = require('sinon'),
|
||||
_ = require('lodash'),
|
||||
|
@ -9,7 +10,8 @@ var fs = require('fs'),
|
|||
|
||||
// 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');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in a new issue