mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[cli] collect extra arguments and merge into settings object
This commit is contained in:
parent
4f5f523946
commit
52570cbaad
16 changed files with 330 additions and 114 deletions
|
@ -18,7 +18,7 @@ If Not Exist "%NODE%" (
|
|||
)
|
||||
|
||||
TITLE Kibana Server
|
||||
"%NODE%" "%DIR%\src\cli" %*
|
||||
"%NODE%" "%DIR%\src\cli\cli" %*
|
||||
|
||||
:finally
|
||||
|
||||
|
|
|
@ -22,5 +22,5 @@ if [ ! -x "$NODE" ]; then
|
|||
fi
|
||||
|
||||
|
||||
CONFIG_PATH="${DIR}/config/kibana.yml" exec "${NODE}" "${DIR}/src/cli" ${@}
|
||||
CONFIG_PATH="${DIR}/config/kibana.yml" exec "${NODE}" "${DIR}/src/cli/cli" ${@}
|
||||
|
||||
|
|
61
src/cli/Command.js
Normal file
61
src/cli/Command.js
Normal file
|
@ -0,0 +1,61 @@
|
|||
'use strict';
|
||||
|
||||
let _ = require('lodash');
|
||||
let Command = require('commander').Command;
|
||||
|
||||
let red = require('./color').red;
|
||||
let yellow = require('./color').yellow;
|
||||
let help = require('./help');
|
||||
|
||||
Command.prototype.error = function (err) {
|
||||
if (err && err.message) err = err.message;
|
||||
|
||||
console.log(
|
||||
`
|
||||
${red(' ERROR ')} ${err}
|
||||
|
||||
${help(this, ' ')}
|
||||
`
|
||||
);
|
||||
};
|
||||
|
||||
Command.prototype.unknownArgv = function (argv) {
|
||||
if (argv) this.__unkownArgv = argv;
|
||||
return (this.__unkownArgv || []).slice(0);
|
||||
};
|
||||
|
||||
Command.prototype.getUnknownOpts = function () {
|
||||
let opts = {};
|
||||
let unknowns = this.unknownArgv();
|
||||
|
||||
while (unknowns.length) {
|
||||
let opt = unknowns.shift().split('=');
|
||||
if (opt[0].slice(0, 2) !== '--') {
|
||||
this.error(`Extra option "${opt[0]}" must start with "--"`);
|
||||
}
|
||||
|
||||
if (opt.length === 1) {
|
||||
if (!unknowns.length || unknowns[0][0] === '-') {
|
||||
this.error(`Extra option "${opt[0]}" must have a value`);
|
||||
}
|
||||
|
||||
opt.push(unknowns.shift());
|
||||
}
|
||||
|
||||
let val = opt[1];
|
||||
try { val = JSON.parse(opt[1]); }
|
||||
catch (e) { val = opt[1]; }
|
||||
|
||||
_.set(opts, opt[0].slice(2), val);
|
||||
}
|
||||
|
||||
return opts;
|
||||
};
|
||||
|
||||
Command.prototype.parseOptions = _.wrap(Command.prototype.parseOptions, function (parse, argv) {
|
||||
let opts = parse.call(this, argv);
|
||||
this.unknownArgv(opts.unknown);
|
||||
return opts;
|
||||
});
|
||||
|
||||
module.exports = Command;
|
|
@ -1,71 +1,40 @@
|
|||
'use strict';
|
||||
|
||||
let _ = require('lodash');
|
||||
let KbnServer = require('../server/KbnServer');
|
||||
let program = require('commander');
|
||||
let fromRoot = require('../utils/fromRoot');
|
||||
let pkg = require('../utils/closestPackageJson').getSync();
|
||||
let readYamlConfig = require('./readYamlConfig');
|
||||
let Command = require('./Command');
|
||||
|
||||
program.description(
|
||||
let argv = require('cluster').isWorker ? JSON.parse(process.env.kbnWorkerArgv) : process.argv.slice();
|
||||
let program = new Command('bin/kibana');
|
||||
|
||||
program
|
||||
.version(pkg.version)
|
||||
.description(
|
||||
'Kibana is an open source (Apache Licensed), browser based analytics ' +
|
||||
'and search dashboard for Elasticsearch.'
|
||||
);
|
||||
program.version(pkg.version);
|
||||
program.option('-e, --elasticsearch <uri>', 'Elasticsearch instance');
|
||||
program.option('-c, --config <path>', 'Path to the config file');
|
||||
program.option('-p, --port <port>', 'The port to bind to', parseInt);
|
||||
program.option('-q, --quiet', 'Turns off logging');
|
||||
program.option('--verbose', 'Turns on verbose logging');
|
||||
program.option('-H, --host <host>', 'The host to bind to');
|
||||
program.option('-l, --log-file <path>', 'The file to log to');
|
||||
program.option(
|
||||
'--plugin-dir <path>',
|
||||
'A path to scan for plugins, this can be specified multiple ' +
|
||||
'times to specify multiple directories'
|
||||
);
|
||||
program.option(
|
||||
'--plugin-path <path>',
|
||||
'A path to a plugin which should be included by the server, ' +
|
||||
'this can be specified multiple times to specify multiple paths'
|
||||
);
|
||||
program.option('--plugins <path>', 'an alias for --plugin-dir');
|
||||
program.option('--dev', 'Run the server with development mode defaults');
|
||||
program.option(
|
||||
'--watch',
|
||||
'Enable watching the source tree and automatically restarting, ' +
|
||||
'enabled by --dev, use --no-watch to disable'
|
||||
);
|
||||
program.parse(process.argv);
|
||||
|
||||
let settings = readYamlConfig(program.config || fromRoot('config/kibana.yml'));
|
||||
let set = _.partial(_.set, settings);
|
||||
let get = _.partial(_.get, settings);
|
||||
// attach commands
|
||||
var serve = require('./commands/serve/serve')(program);
|
||||
|
||||
if (program.dev) {
|
||||
set('env', 'development');
|
||||
set('optimize.watch', true);
|
||||
// check for no command name
|
||||
if (!argv[2] || argv[2][0] === '-') {
|
||||
argv.splice(2, 0, ['serve']);
|
||||
}
|
||||
|
||||
if (program.watch != null) set('optimize.watch', program.watch);
|
||||
if (program.elasticsearch) set('elasticsearch.url', program.elasticsearch);
|
||||
if (program.port) set('server.port', program.port);
|
||||
if (program.host) set('server.host', program.host);
|
||||
if (program.quiet) set('logging.quiet', program.quiet);
|
||||
if (program.logFile) set('logging.dest', program.logFile);
|
||||
|
||||
set('plugins.scanDirs', _.compact([].concat(
|
||||
get('plugins.scanDirs'),
|
||||
program.plugins,
|
||||
program.pluginDir,
|
||||
fromRoot('src/plugins')
|
||||
)));
|
||||
|
||||
set('plugins.paths', [].concat(program.pluginPath || []));
|
||||
|
||||
// Start the KbnServer server with the settings fromt he CLI and YAML file
|
||||
let kibana = new KbnServer(settings);
|
||||
kibana.listen().catch(function (err) {
|
||||
console.log(err.stack);
|
||||
process.exit(1);
|
||||
program
|
||||
.command('help <command>')
|
||||
.description('Get the help for a specific command')
|
||||
.action(function (cmdName) {
|
||||
var cmd = _.find(program.commands, { _name: cmdName });
|
||||
if (!cmd) return this.error(`unknown command ${cmd}`);
|
||||
cmd.help();
|
||||
});
|
||||
|
||||
program
|
||||
.command('*', null, { noHelp: true })
|
||||
.action(function (cmd, options) {
|
||||
program.error(`unknown command ${cmd}`);
|
||||
});
|
||||
|
||||
program.parse(argv);
|
||||
|
|
7
src/cli/color.js
Normal file
7
src/cli/color.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
|
||||
var _ = require('lodash');
|
||||
var ansicolors = require('ansicolors');
|
||||
|
||||
exports.green = _.flow(ansicolors.black, ansicolors.bgGreen);
|
||||
exports.red = _.flow(ansicolors.white, ansicolors.bgRed);
|
||||
exports.yellow = _.flow(ansicolors.black, ansicolors.bgYellow);
|
4
src/cli/commands/serve/devMode/package.json
Normal file
4
src/cli/commands/serve/devMode/package.json
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "devMode",
|
||||
"version": "1.0.0"
|
||||
}
|
67
src/cli/commands/serve/serve.js
Normal file
67
src/cli/commands/serve/serve.js
Normal file
|
@ -0,0 +1,67 @@
|
|||
'use strict';
|
||||
|
||||
let _ = require('lodash');
|
||||
|
||||
let readYamlConfig = require('../../readYamlConfig');
|
||||
let fromRoot = require('../../../utils/fromRoot');
|
||||
let KbnServer = require('../../../server/KbnServer');
|
||||
|
||||
module.exports = function (program) {
|
||||
program
|
||||
.command('serve')
|
||||
.description('Run the kibana server')
|
||||
.allowUnknownOption()
|
||||
.option('-e, --elasticsearch <uri>', 'Elasticsearch instance')
|
||||
.option('-c, --config <path>', 'Path to the config file')
|
||||
.option('-p, --port <port>', 'The port to bind to', parseInt)
|
||||
.option('-q, --quiet', 'Turns off logging')
|
||||
.option('--verbose', 'Turns on verbose logging')
|
||||
.option('-H, --host <host>', 'The host to bind to')
|
||||
.option('-l, --log-file <path>', 'The file to log to')
|
||||
.option(
|
||||
'--plugin-dir <path>',
|
||||
'A path to scan for plugins, this can be specified multiple ' +
|
||||
'times to specify multiple directories'
|
||||
)
|
||||
.option(
|
||||
'--plugin-path <path>',
|
||||
'A path to a plugin which should be included by the server, ' +
|
||||
'this can be specified multiple times to specify multiple paths'
|
||||
)
|
||||
.option('--plugins <path>', 'an alias for --plugin-dir')
|
||||
.option('--dev', 'Run the server with development mode defaults')
|
||||
.option('--no-watch', 'Prevent watching, use with --dev to prevent server restarts')
|
||||
.action(function (opts) {
|
||||
|
||||
if (opts.dev && !opts.noWatch && !require('cluster').isWorker) {
|
||||
// stop processing the action and handoff to watch cluster manager
|
||||
return require('./watch');
|
||||
}
|
||||
|
||||
let settings = readYamlConfig(opts.config || fromRoot('config/kibana.yml'));
|
||||
let set = _.partial(_.set, settings);
|
||||
let get = _.partial(_.get, settings);
|
||||
|
||||
if (opts.dev) {
|
||||
set('env', 'development');
|
||||
set('optimize.watch', opts.watch);
|
||||
}
|
||||
|
||||
if (opts.elasticsearch) set('elasticsearch.url', opts.elasticsearch);
|
||||
if (opts.port) set('server.port', opts.port);
|
||||
if (opts.host) set('server.host', opts.host);
|
||||
if (opts.quiet) set('logging.quiet', opts.quiet);
|
||||
if (opts.logFile) set('logging.dest', opts.logFile);
|
||||
|
||||
set('plugins.scanDirs', _.compact([].concat(
|
||||
get('plugins.scanDirs'),
|
||||
opts.plugins,
|
||||
opts.pluginDir,
|
||||
fromRoot('src/plugins')
|
||||
)));
|
||||
|
||||
set('plugins.paths', [].concat(opts.pluginPath || []));
|
||||
|
||||
return new KbnServer(_.merge(settings, this.getUnknownOpts()));
|
||||
});
|
||||
};
|
88
src/cli/commands/serve/watch.js
Normal file
88
src/cli/commands/serve/watch.js
Normal file
|
@ -0,0 +1,88 @@
|
|||
'use strict';
|
||||
|
||||
let _ = require('lodash');
|
||||
let Gaze = require('gaze').Gaze;
|
||||
let join = require('path').join;
|
||||
let cluster = require('cluster');
|
||||
let ansicolors = require('ansicolors');
|
||||
|
||||
let cliPath = join(__dirname, '..', 'cli.js');
|
||||
let green = require('../color').green;
|
||||
let red = require('../color').red;
|
||||
let yellow = require('../color').yellow;
|
||||
|
||||
console.log(yellow(' Kibana starting '), 'and watching for changes');
|
||||
|
||||
cluster.setupMaster({
|
||||
exec: cliPath,
|
||||
silent: false
|
||||
});
|
||||
|
||||
let baseArgv = [process.execPath, cliPath].concat(_.difference(process.argv.slice(2), ['--no-watch']));
|
||||
let serverArgv = JSON.stringify(baseArgv.concat(['--optimize.enable=false']));
|
||||
let optimizerArgv = JSON.stringify(baseArgv.concat(['--plugins.initialize=false']));
|
||||
|
||||
let changedFiles = [];
|
||||
let server;
|
||||
let startServer = _.debounce(function () {
|
||||
if (server && server.isDead()) {
|
||||
server.kill(); // once "exit" event is received with 0 status, startServer() is called again
|
||||
return;
|
||||
}
|
||||
|
||||
server = cluster.fork({ kbnWorkerArgv: serverArgv });
|
||||
server.on('online', function () {
|
||||
if (!changedFiles.length) {
|
||||
console.log(green(' Kibana Started '));
|
||||
return;
|
||||
}
|
||||
|
||||
let files = changedFiles.splice(0);
|
||||
let prefix = files.length > 1 ? '\n - ' : '';
|
||||
let fileList = files.reduce(function (list, file, i, files) {
|
||||
return `${list || ''}${prefix}"${file}"`;
|
||||
}, '');
|
||||
|
||||
console.log(yellow(' Kibana Restarted '), `due to changes in ${fileList}`);
|
||||
});
|
||||
}, 200);
|
||||
|
||||
let optimizer = cluster.fork({ kbnWorkerArgv: optimizerArgv });
|
||||
optimizer.on('online', startServer);
|
||||
|
||||
cluster.on('exit', function (worker, code) {
|
||||
if (worker === server) {
|
||||
if (code > 0) {
|
||||
console.log(red(' Kibana Crashed '), 'with status code', code);
|
||||
} else {
|
||||
// graceful shutdowns should only happen if we are restarting
|
||||
startServer();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (worker === optimizer) {
|
||||
console.log(red(' optimizer crashed '), 'with status code', code);
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
let gaze = new Gaze([
|
||||
'src/**/*.{js,json,tmpl,yml}',
|
||||
'!src/**/public/',
|
||||
'config/',
|
||||
], {
|
||||
cwd: join(__dirname, '..', '..', '..')
|
||||
});
|
||||
|
||||
// A file has been added/changed/deleted
|
||||
gaze.on('all', function (event, path) {
|
||||
changedFiles.push(path);
|
||||
startServer();
|
||||
});
|
||||
|
||||
gaze.on('error', function (err) {
|
||||
console.log(red(' failed to watch files \n'), err.stack);
|
||||
process.exit(1);
|
||||
});
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"name": "devmode",
|
||||
"main": "devmode.js",
|
||||
"version": "1.0.0"
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
let _ = require('lodash');
|
||||
let nodemon = require('nodemon');
|
||||
let join = require('path').join;
|
||||
let relative = require('path').relative;
|
||||
let normalize = require('path').normalize;
|
||||
let ansicolors = require('ansicolors');
|
||||
|
||||
let root = join(__dirname, '..', '..', '..');
|
||||
let fromRoot = _.restParam(function (segs) {
|
||||
return normalize(join.apply(null, [root].concat(segs)));
|
||||
});
|
||||
let rel = _.partial(relative, root);
|
||||
|
||||
let green = _.flow(ansicolors.black, ansicolors.bgGreen);
|
||||
let red = _.flow(ansicolors.white, ansicolors.bgRed);
|
||||
let yellow = _.flow(ansicolors.black, ansicolors.bgYellow);
|
||||
|
||||
let crash = red(' Kibana Crashed ');
|
||||
let restart = yellow(' Kibana Restarted ');
|
||||
let start = green(' Kibana Started ');
|
||||
let args = _.without(process.argv.slice(2), '--watch');
|
||||
|
||||
console.log(yellow(' Kibana starting '), 'and watching for changes');
|
||||
|
||||
nodemon({
|
||||
script: fromRoot('src/cli/index.js'),
|
||||
args: args,
|
||||
watch: [
|
||||
fromRoot('src/'),
|
||||
fromRoot('config/'),
|
||||
],
|
||||
ignore: fromRoot('src/**/public/'),
|
||||
ext: 'js,json,tmpl,yml'
|
||||
});
|
||||
|
||||
nodemon.on('start', _.bindKey(console, 'log', start));
|
||||
nodemon.on('crash', _.bindKey(console, 'log', crash));
|
||||
nodemon.on('restart', function (files) {
|
||||
var prefix = files.length > 1 ? '\n - ' : '';
|
||||
var fileList = files.reduce(function (list, file, i, files) {
|
||||
return `${list || ''}${prefix}"${rel(file)}"`;
|
||||
}, '');
|
||||
|
||||
console.log(`${restart} due to changes in ${fileList}`);
|
||||
});
|
74
src/cli/help.js
Normal file
74
src/cli/help.js
Normal file
|
@ -0,0 +1,74 @@
|
|||
'use strict';
|
||||
|
||||
var _ = require('lodash');
|
||||
|
||||
module.exports = function (command, spaces) {
|
||||
if (!_.size(command.commands)) {
|
||||
return command.outputHelp();
|
||||
}
|
||||
|
||||
let defCmd = _.find(command.commands, function (cmd) {
|
||||
return cmd._name === 'serve';
|
||||
});
|
||||
|
||||
let desc = !command.description() ? '' : command.description();
|
||||
let cmdDef = !defCmd ? '' : `=${defCmd._name}`;
|
||||
|
||||
return _.trim(
|
||||
`
|
||||
Usage: ${command._name} [command${cmdDef}] [options]
|
||||
|
||||
${desc}
|
||||
|
||||
Commands:
|
||||
${indent(commandsSummary(command), 2)}
|
||||
|
||||
${cmdHelp(defCmd)}
|
||||
`
|
||||
).replace(/^/gm, spaces || '');
|
||||
};
|
||||
|
||||
function indent(str, n) {
|
||||
return String(str || '').trim().replace(/^/gm, _.repeat(' ', n));
|
||||
}
|
||||
|
||||
function commandsSummary(program) {
|
||||
let cmds = _.compact(program.commands.map(function (cmd) {
|
||||
let name = cmd._name;
|
||||
if (name === '*') return;
|
||||
let opts = cmd.options.length ? ' [options]' : '';
|
||||
let args = cmd._args.map(function (arg) {
|
||||
return humanReadableArgName(arg);
|
||||
}).join(' ');
|
||||
|
||||
return [
|
||||
`${name} ${opts} ${args}`,
|
||||
cmd.description()
|
||||
];
|
||||
}));
|
||||
|
||||
let cmdLColWidth = cmds.reduce(function (width, cmd) {
|
||||
return Math.max(width, cmd[0].length);
|
||||
}, 0);
|
||||
|
||||
return cmds.reduce(function (help, cmd) {
|
||||
return `${help || ''}${_.padRight(cmd[0], cmdLColWidth)} ${cmd[1] || ''}\n`;
|
||||
}, '');
|
||||
}
|
||||
|
||||
function cmdHelp(cmd) {
|
||||
if (!cmd) return '';
|
||||
return _.trim(
|
||||
`
|
||||
"${cmd._name}" Options:
|
||||
|
||||
${indent(cmd.optionHelp(), 2)}
|
||||
`
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
function humanReadableArgName(arg) {
|
||||
var nameOutput = arg.name + (arg.variadic === true ? '...' : '');
|
||||
return arg.required ? '<' + nameOutput + '>' : '[' + nameOutput + ']';
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
if (process.argv.slice(2).indexOf('--watch') > -1) require('./dev/watch');
|
||||
else require('./cli');
|
Loading…
Add table
Add a link
Reference in a new issue