Merge pull request #184 from braydonf/cli-fixes
CLI fixes for installing and removing services.
This commit is contained in:
commit
290874a8fb
30
cli/main.js
30
cli/main.js
@ -58,20 +58,23 @@ function main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
program
|
program
|
||||||
.command('add <modules...>')
|
.command('add <services...>')
|
||||||
.alias('install')
|
.alias('install')
|
||||||
.description('Install a module for the current node')
|
.description('Install a service for the current node')
|
||||||
.action(function(modules){
|
.action(function(services){
|
||||||
var configInfo = findConfig(process.cwd());
|
var configInfo = findConfig(process.cwd());
|
||||||
if (!configInfo) {
|
if (!configInfo) {
|
||||||
throw new Error('Could not find configuration, see `bitcore-node create --help`');
|
throw new Error('Could not find configuration, see `bitcore-node create --help`');
|
||||||
}
|
}
|
||||||
var opts = {
|
var opts = {
|
||||||
path: configInfo.path,
|
path: configInfo.path,
|
||||||
modules: modules
|
services: services
|
||||||
};
|
};
|
||||||
add(opts, function() {
|
add(opts, function(err) {
|
||||||
console.log('Successfully added module(s):', modules.join(', '));
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
console.log('Successfully added services(s):', services.join(', '));
|
||||||
});
|
});
|
||||||
}).on('--help', function() {
|
}).on('--help', function() {
|
||||||
console.log(' Examples:');
|
console.log(' Examples:');
|
||||||
@ -82,20 +85,23 @@ function main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
program
|
program
|
||||||
.command('remove <modules...>')
|
.command('remove <services...>')
|
||||||
.alias('uninstall')
|
.alias('uninstall')
|
||||||
.description('Uninstall a module for the current node')
|
.description('Uninstall a service for the current node')
|
||||||
.action(function(modules){
|
.action(function(services){
|
||||||
var configInfo = findConfig(process.cwd());
|
var configInfo = findConfig(process.cwd());
|
||||||
if (!configInfo) {
|
if (!configInfo) {
|
||||||
throw new Error('Could not find configuration, see `bitcore-node create --help`');
|
throw new Error('Could not find configuration, see `bitcore-node create --help`');
|
||||||
}
|
}
|
||||||
var opts = {
|
var opts = {
|
||||||
path: configInfo.path,
|
path: configInfo.path,
|
||||||
modules: modules
|
services: services
|
||||||
};
|
};
|
||||||
remove(opts, function() {
|
remove(opts, function(err) {
|
||||||
console.log('Successfully removed module(s):', modules.join(', '));
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
console.log('Successfully removed services(s):', services.join(', '));
|
||||||
});
|
});
|
||||||
}).on('--help', function() {
|
}).on('--help', function() {
|
||||||
console.log(' Examples:');
|
console.log(' Examples:');
|
||||||
|
|||||||
@ -147,11 +147,6 @@ Node.prototype._instantiateService = function(service) {
|
|||||||
config.node = this;
|
config.node = this;
|
||||||
var mod = new service.module(config);
|
var mod = new service.module(config);
|
||||||
|
|
||||||
$.checkState(
|
|
||||||
mod instanceof BaseService,
|
|
||||||
'Unexpected module instance type for service:' + service.name
|
|
||||||
);
|
|
||||||
|
|
||||||
// include in loaded services
|
// include in loaded services
|
||||||
this.services[service.name] = mod;
|
this.services[service.name] = mod;
|
||||||
|
|
||||||
|
|||||||
@ -94,6 +94,11 @@ function add(options, done) {
|
|||||||
if (err) {
|
if (err) {
|
||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: get the name of the package from the updated package.json
|
||||||
|
// to be able to support other types of installation such as
|
||||||
|
// hosted git urls
|
||||||
|
|
||||||
// add service to bitcore-node.json
|
// add service to bitcore-node.json
|
||||||
addConfig(bitcoreConfigPath, service, next);
|
addConfig(bitcoreConfigPath, service, next);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -10,12 +10,12 @@ var $ = bitcore.util.preconditions;
|
|||||||
var _ = bitcore.deps._;
|
var _ = bitcore.deps._;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will remove a module from bitcore-node.json
|
* Will remove a service from bitcore-node.json
|
||||||
* @param {String} configFilePath - The absolute path to the configuration file
|
* @param {String} configFilePath - The absolute path to the configuration file
|
||||||
* @param {String} module - The name of the module
|
* @param {String} service - The name of the module
|
||||||
* @param {Function} done
|
* @param {Function} done
|
||||||
*/
|
*/
|
||||||
function removeConfig(configFilePath, module, done) {
|
function removeConfig(configFilePath, service, done) {
|
||||||
$.checkArgument(path.isAbsolute(configFilePath), 'An absolute path is expected');
|
$.checkArgument(path.isAbsolute(configFilePath), 'An absolute path is expected');
|
||||||
fs.readFile(configFilePath, function(err, data) {
|
fs.readFile(configFilePath, function(err, data) {
|
||||||
if (err) {
|
if (err) {
|
||||||
@ -23,17 +23,17 @@ function removeConfig(configFilePath, module, done) {
|
|||||||
}
|
}
|
||||||
var config = JSON.parse(data);
|
var config = JSON.parse(data);
|
||||||
$.checkState(
|
$.checkState(
|
||||||
Array.isArray(config.modules),
|
Array.isArray(config.services),
|
||||||
'Configuration file is expected to have a modules array.'
|
'Configuration file is expected to have a services array.'
|
||||||
);
|
);
|
||||||
// remove the module from the configuration
|
// remove the service from the configuration
|
||||||
for (var i = 0; i < config.modules.length; i++) {
|
for (var i = 0; i < config.services.length; i++) {
|
||||||
if (config.modules[i] === module) {
|
if (config.services[i] === service) {
|
||||||
config.modules.splice(i, 1);
|
config.services.splice(i, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
config.modules = _.unique(config.modules);
|
config.services = _.unique(config.services);
|
||||||
config.modules.sort(function(a, b) {
|
config.services.sort(function(a, b) {
|
||||||
return a > b;
|
return a > b;
|
||||||
});
|
});
|
||||||
fs.writeFile(configFilePath, JSON.stringify(config, null, 2), done);
|
fs.writeFile(configFilePath, JSON.stringify(config, null, 2), done);
|
||||||
@ -41,16 +41,16 @@ function removeConfig(configFilePath, module, done) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will uninstall a Node.js module and remove from package.json.
|
* Will uninstall a Node.js service and remove from package.json.
|
||||||
* @param {String} configDir - The absolute configuration directory path
|
* @param {String} configDir - The absolute configuration directory path
|
||||||
* @param {String} module - The name of the module
|
* @param {String} service - The name of the service
|
||||||
* @param {Function} done
|
* @param {Function} done
|
||||||
*/
|
*/
|
||||||
function uninstallModule(configDir, module, done) {
|
function uninstallService(configDir, service, done) {
|
||||||
$.checkArgument(path.isAbsolute(configDir), 'An absolute path is expected');
|
$.checkArgument(path.isAbsolute(configDir), 'An absolute path is expected');
|
||||||
$.checkArgument(_.isString(module), 'A string is expected for the module argument');
|
$.checkArgument(_.isString(service), 'A string is expected for the service argument');
|
||||||
|
|
||||||
var child = spawn('npm', ['uninstall', module, '--save'], {cwd: configDir});
|
var child = spawn('npm', ['uninstall', service, '--save'], {cwd: configDir});
|
||||||
|
|
||||||
child.stdout.on('data', function(data) {
|
child.stdout.on('data', function(data) {
|
||||||
process.stdout.write(data);
|
process.stdout.write(data);
|
||||||
@ -62,7 +62,7 @@ function uninstallModule(configDir, module, done) {
|
|||||||
|
|
||||||
child.on('close', function(code) {
|
child.on('close', function(code) {
|
||||||
if (code !== 0) {
|
if (code !== 0) {
|
||||||
return done(new Error('There was an error uninstalling module: ' + module));
|
return done(new Error('There was an error uninstalling service(s): ' + service));
|
||||||
} else {
|
} else {
|
||||||
return done();
|
return done();
|
||||||
}
|
}
|
||||||
@ -70,26 +70,26 @@ function uninstallModule(configDir, module, done) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will remove a Node.js module if it is installed.
|
* Will remove a Node.js service if it is installed.
|
||||||
* @param {String} configDir - The absolute configuration directory path
|
* @param {String} configDir - The absolute configuration directory path
|
||||||
* @param {String} module - The name of the module
|
* @param {String} service - The name of the service
|
||||||
* @param {Function} done
|
* @param {Function} done
|
||||||
*/
|
*/
|
||||||
function removeModule(configDir, module, done) {
|
function removeService(configDir, service, done) {
|
||||||
$.checkArgument(path.isAbsolute(configDir), 'An absolute path is expected');
|
$.checkArgument(path.isAbsolute(configDir), 'An absolute path is expected');
|
||||||
$.checkArgument(_.isString(module), 'A string is expected for the module argument');
|
$.checkArgument(_.isString(service), 'A string is expected for the service argument');
|
||||||
|
|
||||||
// check if the module is installed
|
// check if the service is installed
|
||||||
npm.load(function(err) {
|
npm.load(function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return done(err);
|
return done(err);
|
||||||
}
|
}
|
||||||
npm.commands.ls([module], true /*silent*/, function(err, data, lite) {
|
npm.commands.ls([service], true /*silent*/, function(err, data, lite) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return done(err);
|
return done(err);
|
||||||
}
|
}
|
||||||
if (lite.dependencies) {
|
if (lite.dependencies) {
|
||||||
uninstallModule(configDir, module, done);
|
uninstallService(configDir, service, done);
|
||||||
} else {
|
} else {
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
@ -99,10 +99,10 @@ function removeModule(configDir, module, done) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will remove the Node.js module and from the bitcore-node configuration.
|
* Will remove the Node.js service and from the bitcore-node configuration.
|
||||||
* @param {String} options.cwd - The current working directory
|
* @param {String} options.cwd - The current working directory
|
||||||
* @param {String} options.dirname - The bitcore-node configuration directory
|
* @param {String} options.dirname - The bitcore-node configuration directory
|
||||||
* @param {Array} options.modules - An array of strings of module names
|
* @param {Array} options.services - An array of strings of service names
|
||||||
* @param {Function} done - A callback function called when finished
|
* @param {Function} done - A callback function called when finished
|
||||||
*/
|
*/
|
||||||
function remove(options, done) {
|
function remove(options, done) {
|
||||||
@ -112,10 +112,10 @@ function remove(options, done) {
|
|||||||
_.isString(options.path) && path.isAbsolute(options.path),
|
_.isString(options.path) && path.isAbsolute(options.path),
|
||||||
'An absolute path is expected'
|
'An absolute path is expected'
|
||||||
);
|
);
|
||||||
$.checkArgument(Array.isArray(options.modules));
|
$.checkArgument(Array.isArray(options.services));
|
||||||
|
|
||||||
var configPath = options.path;
|
var configPath = options.path;
|
||||||
var modules = options.modules;
|
var services = options.services;
|
||||||
|
|
||||||
var bitcoreConfigPath = path.resolve(configPath, 'bitcore-node.json');
|
var bitcoreConfigPath = path.resolve(configPath, 'bitcore-node.json');
|
||||||
var packagePath = path.resolve(configPath, 'package.json');
|
var packagePath = path.resolve(configPath, 'package.json');
|
||||||
@ -127,15 +127,15 @@ function remove(options, done) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async.eachSeries(
|
async.eachSeries(
|
||||||
modules,
|
services,
|
||||||
function(module, next) {
|
function(service, next) {
|
||||||
// if the module is installed remove it
|
// if the service is installed remove it
|
||||||
removeModule(configPath, module, function(err) {
|
removeService(configPath, service, function(err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
// remove module to bitcore-node.json
|
// remove service to bitcore-node.json
|
||||||
removeConfig(bitcoreConfigPath, module, next);
|
removeConfig(bitcoreConfigPath, service, next);
|
||||||
});
|
});
|
||||||
}, done
|
}, done
|
||||||
);
|
);
|
||||||
|
|||||||
@ -20,11 +20,15 @@ log.debug = function() {};
|
|||||||
* }
|
* }
|
||||||
* ]
|
* ]
|
||||||
* @param {Function} req - The require function to use
|
* @param {Function} req - The require function to use
|
||||||
|
* @param {Array} cwd - The local path (for requiring services)
|
||||||
* @param {Object} config
|
* @param {Object} config
|
||||||
* @param {Array} config.services - An array of strings of service names.
|
* @param {Array} config.services - An array of strings of service names.
|
||||||
* @returns {Array}
|
* @returns {Array}
|
||||||
*/
|
*/
|
||||||
function setupServices(req, config) {
|
function setupServices(req, cwd, config) {
|
||||||
|
|
||||||
|
module.paths.push(path.resolve(cwd, './node_modules'));
|
||||||
|
|
||||||
var services = [];
|
var services = [];
|
||||||
if (config.services) {
|
if (config.services) {
|
||||||
for (var i = 0; i < config.services.length; i++) {
|
for (var i = 0; i < config.services.length; i++) {
|
||||||
@ -160,7 +164,7 @@ function registerExitHandlers(proc, node) {
|
|||||||
function start(options) {
|
function start(options) {
|
||||||
|
|
||||||
var fullConfig = _.clone(options.config);
|
var fullConfig = _.clone(options.config);
|
||||||
fullConfig.services = setupServices(require, options.config);
|
fullConfig.services = setupServices(require, options.path, options.config);
|
||||||
fullConfig.datadir = path.resolve(options.path, options.config.datadir);
|
fullConfig.datadir = path.resolve(options.path, options.config.datadir);
|
||||||
|
|
||||||
var node = new BitcoreNode(fullConfig);
|
var node = new BitcoreNode(fullConfig);
|
||||||
|
|||||||
@ -47,14 +47,14 @@
|
|||||||
"async": "^1.3.0",
|
"async": "^1.3.0",
|
||||||
"bindings": "^1.2.1",
|
"bindings": "^1.2.1",
|
||||||
"bitcore": "^0.13.0",
|
"bitcore": "^0.13.0",
|
||||||
"colors": "^1.1.2",
|
|
||||||
"body-parser": "^1.13.3",
|
"body-parser": "^1.13.3",
|
||||||
|
"colors": "^1.1.2",
|
||||||
"commander": "^2.8.1",
|
"commander": "^2.8.1",
|
||||||
"errno": "^0.1.4",
|
"errno": "^0.1.4",
|
||||||
|
"express": "^4.13.3",
|
||||||
"leveldown": "^1.4.1",
|
"leveldown": "^1.4.1",
|
||||||
"levelup": "^1.2.1",
|
"levelup": "^1.2.1",
|
||||||
"liftoff": "^2.1.0",
|
"liftoff": "^2.1.0",
|
||||||
"express": "^4.13.3",
|
|
||||||
"memdown": "^1.0.0",
|
"memdown": "^1.0.0",
|
||||||
"mkdirp": "0.5.0",
|
"mkdirp": "0.5.0",
|
||||||
"nan": "1.3.0",
|
"nan": "1.3.0",
|
||||||
|
|||||||
@ -15,7 +15,7 @@ describe('#remove', function() {
|
|||||||
var testDir = path.resolve(basePath, 'temporary-test-data');
|
var testDir = path.resolve(basePath, 'temporary-test-data');
|
||||||
var startConfig = {
|
var startConfig = {
|
||||||
name: 'My Node',
|
name: 'My Node',
|
||||||
modules: ['a', 'b', 'c']
|
services: ['a', 'b', 'c']
|
||||||
};
|
};
|
||||||
var startPackage = {};
|
var startPackage = {};
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ describe('#remove', function() {
|
|||||||
it('will give an error if expected files do not exist', function(done) {
|
it('will give an error if expected files do not exist', function(done) {
|
||||||
remove({
|
remove({
|
||||||
path: path.resolve(testDir, 's0'),
|
path: path.resolve(testDir, 's0'),
|
||||||
modules: ['b']
|
services: ['b']
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
should.exist(err);
|
should.exist(err);
|
||||||
err.message.match(/^Invalid state/);
|
err.message.match(/^Invalid state/);
|
||||||
@ -64,7 +64,7 @@ describe('#remove', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('will update bitcore-node.json modules', function(done) {
|
it('will update bitcore-node.json services', function(done) {
|
||||||
var spawn = sinon.stub().returns({
|
var spawn = sinon.stub().returns({
|
||||||
stdout: {
|
stdout: {
|
||||||
on: sinon.stub()
|
on: sinon.stub()
|
||||||
@ -89,12 +89,12 @@ describe('#remove', function() {
|
|||||||
});
|
});
|
||||||
removetest({
|
removetest({
|
||||||
path: path.resolve(testDir, 's0/s1/'),
|
path: path.resolve(testDir, 's0/s1/'),
|
||||||
modules: ['b']
|
services: ['b']
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
should.not.exist(err);
|
should.not.exist(err);
|
||||||
var configPath = path.resolve(testDir, 's0/s1/bitcore-node.json');
|
var configPath = path.resolve(testDir, 's0/s1/bitcore-node.json');
|
||||||
var config = JSON.parse(fs.readFileSync(configPath));
|
var config = JSON.parse(fs.readFileSync(configPath));
|
||||||
config.modules.should.deep.equal(['a', 'c']);
|
config.services.should.deep.equal(['a', 'c']);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -125,10 +125,10 @@ describe('#remove', function() {
|
|||||||
|
|
||||||
removetest({
|
removetest({
|
||||||
path: path.resolve(testDir, 's0/s1/'),
|
path: path.resolve(testDir, 's0/s1/'),
|
||||||
modules: ['b']
|
services: ['b']
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
should.exist(err);
|
should.exist(err);
|
||||||
err.message.should.equal('There was an error uninstalling module: b');
|
err.message.should.equal('There was an error uninstalling service(s): b');
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -9,6 +9,7 @@ var start = require('../../lib/scaffold/start');
|
|||||||
|
|
||||||
describe('#start', function() {
|
describe('#start', function() {
|
||||||
describe('#setupServices', function() {
|
describe('#setupServices', function() {
|
||||||
|
var cwd = process.cwd();
|
||||||
var setupServices = proxyquire('../../lib/scaffold/start', {}).setupServices;
|
var setupServices = proxyquire('../../lib/scaffold/start', {}).setupServices;
|
||||||
it('will require an internal module', function() {
|
it('will require an internal module', function() {
|
||||||
function InternalService() {}
|
function InternalService() {}
|
||||||
@ -28,7 +29,7 @@ describe('#start', function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var services = setupServices(testRequire, config);
|
var services = setupServices(testRequire, cwd, config);
|
||||||
services[0].name.should.equal('internal');
|
services[0].name.should.equal('internal');
|
||||||
services[0].config.should.deep.equal({param: 'value'});
|
services[0].config.should.deep.equal({param: 'value'});
|
||||||
services[0].module.should.equal(InternalService);
|
services[0].module.should.equal(InternalService);
|
||||||
@ -53,7 +54,7 @@ describe('#start', function() {
|
|||||||
var config = {
|
var config = {
|
||||||
services: ['local']
|
services: ['local']
|
||||||
};
|
};
|
||||||
var services = setupServices(testRequire, config);
|
var services = setupServices(testRequire, cwd, config);
|
||||||
services[0].name.should.equal('local');
|
services[0].name.should.equal('local');
|
||||||
services[0].module.should.equal(LocalService);
|
services[0].module.should.equal(LocalService);
|
||||||
});
|
});
|
||||||
@ -78,7 +79,7 @@ describe('#start', function() {
|
|||||||
var config = {
|
var config = {
|
||||||
services: ['local']
|
services: ['local']
|
||||||
};
|
};
|
||||||
var services = setupServices(testRequire, config);
|
var services = setupServices(testRequire, cwd, config);
|
||||||
services[0].name.should.equal('local');
|
services[0].name.should.equal('local');
|
||||||
services[0].module.should.equal(LocalService);
|
services[0].module.should.equal(LocalService);
|
||||||
});
|
});
|
||||||
@ -91,7 +92,7 @@ describe('#start', function() {
|
|||||||
services: ['bitcoind']
|
services: ['bitcoind']
|
||||||
};
|
};
|
||||||
(function() {
|
(function() {
|
||||||
setupServices(testRequire, config);
|
setupServices(testRequire, cwd, config);
|
||||||
}).should.throw('Could not load service');
|
}).should.throw('Could not load service');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user