CLI refactor with commander (#6058)
* CLI refactor with commander - Modularized the functionality - All functionality done directly from `./nodebb` now (still available from `app` for backwards compatibility) - Moved all CLI code from `./nodebb` to `src/cli` - Fixed `nodebb.bat` to work from any location, like `./nodebb`, and also hides command output - Overwrite some commander methods to add CLI color support - Added `./nodebb info` for quick info including git hash, NodeBB version, node version, and some database info - Refactored `./nodebb reset` to allow multiple resets at once - Changed `./nodebb restart` to essentially stop and start, as Windows doesn't support signals - Added `-l, --log` option which works on `./nodebb start` and `./nodebb restart` to show logging, like `./nodebb slog` - Expanded `-d, --dev` option which works on them as well, like `./nodebb dev` - Improvements to self-help. `./nodebb build -h` will output all possible targets - `./nodebb reset` explains usage better * Fix some style inconsistencies * Fix prestart being required before modules installed * Fix travis failures * Fix `help` command to output help for subcommands * Pick steps of the upgrade process to run * Fix formatting for upgrade help * Fix web installerv1.18.x
parent
c731661a39
commit
ae24bca16e
@ -1 +1 @@
|
|||||||
node ./nodebb %*
|
@echo off && cd %~dp0 && node ./src/cli %*
|
||||||
|
@ -0,0 +1,127 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
|
||||||
|
// override commander functions
|
||||||
|
// to include color styling in the output
|
||||||
|
// so the CLI looks nice
|
||||||
|
|
||||||
|
var Command = require('commander').Command;
|
||||||
|
|
||||||
|
var commandColor = 'yellow';
|
||||||
|
var optionColor = 'cyan';
|
||||||
|
var argColor = 'magenta';
|
||||||
|
var subCommandColor = 'green';
|
||||||
|
var subOptionColor = 'blue';
|
||||||
|
var subArgColor = 'red';
|
||||||
|
|
||||||
|
Command.prototype.helpInformation = function () {
|
||||||
|
var desc = [];
|
||||||
|
if (this._description) {
|
||||||
|
desc = [
|
||||||
|
' ' + this._description,
|
||||||
|
'',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
var cmdName = this._name;
|
||||||
|
if (this._alias) {
|
||||||
|
cmdName = cmdName + ' | ' + this._alias;
|
||||||
|
}
|
||||||
|
var usage = [
|
||||||
|
'',
|
||||||
|
' Usage: ' + cmdName[commandColor] + ' '.reset + this.usage(),
|
||||||
|
'',
|
||||||
|
];
|
||||||
|
|
||||||
|
var cmds = [];
|
||||||
|
var commandHelp = this.commandHelp();
|
||||||
|
if (commandHelp) {
|
||||||
|
cmds = [commandHelp];
|
||||||
|
}
|
||||||
|
|
||||||
|
var options = [
|
||||||
|
'',
|
||||||
|
' Options:',
|
||||||
|
'',
|
||||||
|
'' + this.optionHelp().replace(/^/gm, ' '),
|
||||||
|
'',
|
||||||
|
];
|
||||||
|
|
||||||
|
return usage
|
||||||
|
.concat(desc)
|
||||||
|
.concat(options)
|
||||||
|
.concat(cmds)
|
||||||
|
.join('\n'.reset);
|
||||||
|
};
|
||||||
|
|
||||||
|
function humanReadableArgName(arg) {
|
||||||
|
var nameOutput = arg.name + (arg.variadic === true ? '...' : '');
|
||||||
|
|
||||||
|
return arg.required ? '<' + nameOutput + '>' : '[' + nameOutput + ']';
|
||||||
|
}
|
||||||
|
|
||||||
|
Command.prototype.usage = function () {
|
||||||
|
var args = this._args.map(function (arg) {
|
||||||
|
return humanReadableArgName(arg);
|
||||||
|
});
|
||||||
|
|
||||||
|
var usage = '[options]'[optionColor] +
|
||||||
|
(this.commands.length ? ' [command]' : '')[subCommandColor] +
|
||||||
|
(this._args.length ? ' ' + args.join(' ') : '')[argColor];
|
||||||
|
|
||||||
|
return usage;
|
||||||
|
};
|
||||||
|
|
||||||
|
function pad(str, width) {
|
||||||
|
var len = Math.max(0, width - str.length);
|
||||||
|
return str + Array(len + 1).join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
Command.prototype.commandHelp = function () {
|
||||||
|
if (!this.commands.length) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
var commands = this.commands.filter(function (cmd) {
|
||||||
|
return !cmd._noHelp;
|
||||||
|
}).map(function (cmd) {
|
||||||
|
var args = cmd._args.map(function (arg) {
|
||||||
|
return humanReadableArgName(arg);
|
||||||
|
}).join(' ');
|
||||||
|
|
||||||
|
return [
|
||||||
|
cmd._name[subCommandColor] +
|
||||||
|
(cmd._alias ? ' | ' + cmd._alias : '')[subCommandColor] +
|
||||||
|
(cmd.options.length ? ' [options]' : '')[subOptionColor] +
|
||||||
|
' ' + args[subArgColor],
|
||||||
|
cmd._description,
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
var width = commands.reduce(function (max, command) {
|
||||||
|
return Math.max(max, command[0].length);
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'',
|
||||||
|
' Commands:',
|
||||||
|
'',
|
||||||
|
commands.map(function (cmd) {
|
||||||
|
var desc = cmd[1] ? ' ' + cmd[1] : '';
|
||||||
|
return pad(cmd[0], width) + desc;
|
||||||
|
}).join('\n').replace(/^/gm, ' '),
|
||||||
|
'',
|
||||||
|
].join('\n');
|
||||||
|
};
|
||||||
|
|
||||||
|
Command.prototype.optionHelp = function () {
|
||||||
|
var width = this.largestOptionLength();
|
||||||
|
|
||||||
|
// Append the help information
|
||||||
|
return this.options
|
||||||
|
.map(function (option) {
|
||||||
|
return pad(option.flags, width)[optionColor] + ' ' + option.description;
|
||||||
|
})
|
||||||
|
.concat([pad('-h, --help', width)[optionColor] + ' output usage information'])
|
||||||
|
.join('\n');
|
||||||
|
};
|
@ -0,0 +1,265 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var fs = require('fs');
|
||||||
|
var path = require('path');
|
||||||
|
|
||||||
|
var packageInstall = require('../meta/package-install');
|
||||||
|
var dirname = require('./paths').baseDir;
|
||||||
|
|
||||||
|
// check to make sure dependencies are installed
|
||||||
|
try {
|
||||||
|
fs.readFileSync(path.join(dirname, 'package.json'));
|
||||||
|
fs.readFileSync(path.join(dirname, 'node_modules/async/package.json'));
|
||||||
|
} catch (e) {
|
||||||
|
if (e.code === 'ENOENT') {
|
||||||
|
process.stdout.write('Dependencies not yet installed.\n');
|
||||||
|
process.stdout.write('Installing them now...\n\n');
|
||||||
|
|
||||||
|
packageInstall.updatePackageFile();
|
||||||
|
packageInstall.preserveExtraneousPlugins();
|
||||||
|
packageInstall.npmInstallProduction();
|
||||||
|
|
||||||
|
require('colors');
|
||||||
|
process.stdout.write('OK'.green + '\n'.reset);
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
require('colors');
|
||||||
|
var nconf = require('nconf');
|
||||||
|
var program = require('commander');
|
||||||
|
|
||||||
|
var pkg = require('../../package.json');
|
||||||
|
var file = require('../file');
|
||||||
|
var prestart = require('../prestart');
|
||||||
|
|
||||||
|
program
|
||||||
|
.name('./nodebb')
|
||||||
|
.description('Welcome to NodeBB')
|
||||||
|
.version(pkg.version)
|
||||||
|
.option('--json-logging', 'Output to logs in JSON format', false)
|
||||||
|
.option('--log-level <level>', 'Default logging level to use', 'info')
|
||||||
|
.option('-d, --dev', 'Development mode, including verbose logging', false)
|
||||||
|
.option('-l, --log', 'Log subprocess output to console', false)
|
||||||
|
.option('-c, --config <value>', 'Specify a config file', 'config.json')
|
||||||
|
.parse(process.argv);
|
||||||
|
|
||||||
|
nconf.argv().env({
|
||||||
|
separator: '__',
|
||||||
|
});
|
||||||
|
|
||||||
|
var env = program.dev ? 'development' : (process.env.NODE_ENV || 'production');
|
||||||
|
process.env.NODE_ENV = env;
|
||||||
|
global.env = env;
|
||||||
|
|
||||||
|
prestart.setupWinston();
|
||||||
|
|
||||||
|
// Alternate configuration file support
|
||||||
|
var configFile = path.resolve(dirname, program.config);
|
||||||
|
var configExists = file.existsSync(configFile) || (nconf.get('url') && nconf.get('secret') && nconf.get('database'));
|
||||||
|
|
||||||
|
prestart.loadConfig(configFile);
|
||||||
|
prestart.versionCheck();
|
||||||
|
|
||||||
|
if (!configExists && process.argv[2] !== 'setup') {
|
||||||
|
require('./setup').webInstall();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// running commands
|
||||||
|
program
|
||||||
|
.command('start')
|
||||||
|
.description('Start the NodeBB server')
|
||||||
|
.action(function () {
|
||||||
|
require('./running').start(program);
|
||||||
|
});
|
||||||
|
program
|
||||||
|
.command('slog', null, {
|
||||||
|
noHelp: true,
|
||||||
|
})
|
||||||
|
.description('Start the NodeBB server and view the live output log')
|
||||||
|
.action(function () {
|
||||||
|
program.log = true;
|
||||||
|
require('./running').start(program);
|
||||||
|
});
|
||||||
|
program
|
||||||
|
.command('dev', null, {
|
||||||
|
noHelp: true,
|
||||||
|
})
|
||||||
|
.description('Start NodeBB in verbose development mode')
|
||||||
|
.action(function () {
|
||||||
|
program.dev = true;
|
||||||
|
process.env.NODE_ENV = 'development';
|
||||||
|
global.env = 'development';
|
||||||
|
require('./running').start(program);
|
||||||
|
});
|
||||||
|
program
|
||||||
|
.command('stop')
|
||||||
|
.description('Stop the NodeBB server')
|
||||||
|
.action(function () {
|
||||||
|
require('./running').stop(program);
|
||||||
|
});
|
||||||
|
program
|
||||||
|
.command('restart')
|
||||||
|
.description('Restart the NodeBB server')
|
||||||
|
.action(function () {
|
||||||
|
require('./running').restart(program);
|
||||||
|
});
|
||||||
|
program
|
||||||
|
.command('status')
|
||||||
|
.description('Check the running status of the NodeBB server')
|
||||||
|
.action(function () {
|
||||||
|
require('./running').status(program);
|
||||||
|
});
|
||||||
|
program
|
||||||
|
.command('log')
|
||||||
|
.description('Open the output log (useful for debugging)')
|
||||||
|
.action(function () {
|
||||||
|
require('./running').log(program);
|
||||||
|
});
|
||||||
|
|
||||||
|
// management commands
|
||||||
|
program
|
||||||
|
.command('setup')
|
||||||
|
.description('Run the NodeBB setup script')
|
||||||
|
.action(function () {
|
||||||
|
require('./setup').setup();
|
||||||
|
});
|
||||||
|
|
||||||
|
program
|
||||||
|
.command('install')
|
||||||
|
.description('Launch the NodeBB web installer for configuration setup')
|
||||||
|
.action(function () {
|
||||||
|
require('./setup').webInstall();
|
||||||
|
});
|
||||||
|
program
|
||||||
|
.command('build [targets...]')
|
||||||
|
.description('Compile static assets ' + '(JS, CSS, templates, languages, sounds)'.red)
|
||||||
|
.action(function (targets) {
|
||||||
|
require('./manage').build(targets.length ? targets : true);
|
||||||
|
})
|
||||||
|
.on('--help', function () {
|
||||||
|
require('./manage').buildTargets();
|
||||||
|
});
|
||||||
|
program
|
||||||
|
.command('activate [plugin]')
|
||||||
|
.description('Activate a plugin for the next startup of NodeBB (nodebb-plugin- prefix is optional)')
|
||||||
|
.action(function (plugin) {
|
||||||
|
require('./manage').activate(plugin);
|
||||||
|
});
|
||||||
|
program
|
||||||
|
.command('plugins')
|
||||||
|
.action(function () {
|
||||||
|
require('./manage').listPlugins();
|
||||||
|
})
|
||||||
|
.description('List all installed plugins');
|
||||||
|
program
|
||||||
|
.command('events')
|
||||||
|
.description('Outputs the last ten (10) administrative events recorded by NodeBB')
|
||||||
|
.action(function () {
|
||||||
|
require('./manage').listEvents();
|
||||||
|
});
|
||||||
|
program
|
||||||
|
.command('info')
|
||||||
|
.description('Outputs various system info')
|
||||||
|
.action(function () {
|
||||||
|
require('./manage').info();
|
||||||
|
});
|
||||||
|
|
||||||
|
// reset
|
||||||
|
var resetCommand = program.command('reset');
|
||||||
|
|
||||||
|
resetCommand
|
||||||
|
.description('Reset plugins, themes, settings, etc')
|
||||||
|
.option('-t, --theme [theme]', 'Reset to [theme] or to the default theme')
|
||||||
|
.option('-p, --plugin [plugin]', 'Disable [plugin] or all plugins')
|
||||||
|
.option('-w, --widgets', 'Disable all widgets')
|
||||||
|
.option('-s, --settings', 'Reset settings to their default values')
|
||||||
|
.option('-a, --all', 'All of the above')
|
||||||
|
.action(function (options) {
|
||||||
|
var valid = ['theme', 'plugin', 'widgets', 'settings', 'all'].some(function (x) {
|
||||||
|
return options[x];
|
||||||
|
});
|
||||||
|
if (!valid) {
|
||||||
|
process.stdout.write('\n No valid options passed in, so nothing was reset.\n'.red);
|
||||||
|
resetCommand.help();
|
||||||
|
}
|
||||||
|
|
||||||
|
require('./reset').reset(options, function (err) {
|
||||||
|
if (err) { throw err; }
|
||||||
|
require('../meta/build').buildAll(function (err) {
|
||||||
|
if (err) { throw err; }
|
||||||
|
|
||||||
|
process.exit();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// upgrades
|
||||||
|
program
|
||||||
|
.command('upgrade [scripts...]')
|
||||||
|
.description('Run NodeBB upgrade scripts and ensure packages are up-to-date, or run a particular upgrade script')
|
||||||
|
.option('-m, --package', 'Update package.json from defaults', false)
|
||||||
|
.option('-i, --install', 'Bringing base dependencies up to date', false)
|
||||||
|
.option('-p, --plugins', 'Check installed plugins for updates', false)
|
||||||
|
.option('-s, --schema', 'Update NodeBB data store schema', false)
|
||||||
|
.option('-b, --build', 'Rebuild assets', false)
|
||||||
|
.on('--help', function () {
|
||||||
|
process.stdout.write(
|
||||||
|
'\n' +
|
||||||
|
'When running particular upgrade scripts, options are ignored.\n' +
|
||||||
|
'By default all options are enabled. Passing any options disables that default.\n' +
|
||||||
|
'Only package and dependency updates: ' + './nodebb upgrade -mi\n'.yellow +
|
||||||
|
'Only database update: ' + './nodebb upgrade -d\n\n'.yellow
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.action(function (scripts, options) {
|
||||||
|
require('./upgrade').upgrade(scripts.length ? scripts : true, options);
|
||||||
|
});
|
||||||
|
|
||||||
|
program
|
||||||
|
.command('upgrade-plugins', null, {
|
||||||
|
noHelp: true,
|
||||||
|
})
|
||||||
|
.alias('upgradePlugins')
|
||||||
|
.description('Upgrade plugins')
|
||||||
|
.action(function () {
|
||||||
|
require('./upgrade-plugins').upgradePlugins(function (err) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
process.stdout.write('OK\n'.green);
|
||||||
|
process.exit();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
program
|
||||||
|
.command('help [command]')
|
||||||
|
.description('Display help for [command]')
|
||||||
|
.action(function (name) {
|
||||||
|
if (!name) {
|
||||||
|
return program.help();
|
||||||
|
}
|
||||||
|
|
||||||
|
var command = program.commands.find(function (command) { return command._name === name; });
|
||||||
|
if (command) {
|
||||||
|
command.help();
|
||||||
|
} else {
|
||||||
|
program.help();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
program
|
||||||
|
.command('*', {}, {
|
||||||
|
noHelp: true,
|
||||||
|
})
|
||||||
|
.action(function () {
|
||||||
|
program.help();
|
||||||
|
});
|
||||||
|
|
||||||
|
require('./colors');
|
||||||
|
|
||||||
|
program.executables = false;
|
||||||
|
|
||||||
|
program.parse(process.argv);
|
@ -0,0 +1,143 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var async = require('async');
|
||||||
|
var winston = require('winston');
|
||||||
|
var childProcess = require('child_process');
|
||||||
|
var _ = require('lodash');
|
||||||
|
|
||||||
|
var build = require('../meta/build');
|
||||||
|
var db = require('../database');
|
||||||
|
var plugins = require('../plugins');
|
||||||
|
var events = require('../events');
|
||||||
|
var reset = require('./reset');
|
||||||
|
|
||||||
|
function buildTargets() {
|
||||||
|
var aliases = build.aliases;
|
||||||
|
var length = 0;
|
||||||
|
var output = Object.keys(aliases).map(function (name) {
|
||||||
|
var arr = aliases[name];
|
||||||
|
if (name.length > length) {
|
||||||
|
length = name.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [name, arr.join(', ')];
|
||||||
|
}).map(function (tuple) {
|
||||||
|
return ' ' + _.padEnd('"' + tuple[0] + '"', length + 2).magenta + ' | ' + tuple[1];
|
||||||
|
}).join('\n');
|
||||||
|
process.stdout.write(
|
||||||
|
'\n\n Build targets:\n' +
|
||||||
|
('\n ' + _.padEnd('Target', length + 2) + ' | Aliases').green +
|
||||||
|
'\n ------------------------------------------------------\n'.blue +
|
||||||
|
output + '\n\n'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function activate(plugin) {
|
||||||
|
if (plugin.startsWith('nodebb-theme-')) {
|
||||||
|
reset.reset({
|
||||||
|
theme: plugin,
|
||||||
|
}, function (err) {
|
||||||
|
if (err) { throw err; }
|
||||||
|
process.exit();
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
async.waterfall([
|
||||||
|
function (next) {
|
||||||
|
db.init(next);
|
||||||
|
},
|
||||||
|
function (next) {
|
||||||
|
if (!plugin.startsWith('nodebb-')) {
|
||||||
|
// Allow omission of `nodebb-plugin-`
|
||||||
|
plugin = 'nodebb-plugin-' + plugin;
|
||||||
|
}
|
||||||
|
plugins.isInstalled(plugin, next);
|
||||||
|
},
|
||||||
|
function (isInstalled, next) {
|
||||||
|
if (!isInstalled) {
|
||||||
|
return next(new Error('plugin not installed'));
|
||||||
|
}
|
||||||
|
|
||||||
|
winston.info('Activating plugin `%s`', plugin);
|
||||||
|
db.sortedSetAdd('plugins:active', 0, plugin, next);
|
||||||
|
},
|
||||||
|
function (next) {
|
||||||
|
events.log({
|
||||||
|
type: 'plugin-activate',
|
||||||
|
text: plugin,
|
||||||
|
}, next);
|
||||||
|
},
|
||||||
|
], function (err) {
|
||||||
|
if (err) {
|
||||||
|
winston.error('An error occurred during plugin activation', err);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function listPlugins() {
|
||||||
|
async.waterfall([
|
||||||
|
db.init,
|
||||||
|
function (next) {
|
||||||
|
db.getSortedSetRange('plugins:active', 0, -1, next);
|
||||||
|
},
|
||||||
|
function (plugins) {
|
||||||
|
winston.info('Active plugins: \n\t - ' + plugins.join('\n\t - '));
|
||||||
|
process.exit();
|
||||||
|
},
|
||||||
|
], function (err) {
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function listEvents() {
|
||||||
|
async.series([
|
||||||
|
db.init,
|
||||||
|
events.output,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function info() {
|
||||||
|
async.waterfall([
|
||||||
|
function (next) {
|
||||||
|
var version = require('../../package.json').version;
|
||||||
|
process.stdout.write('\n version: ' + version);
|
||||||
|
|
||||||
|
process.stdout.write('\n Node ver: ' + process.version);
|
||||||
|
next();
|
||||||
|
},
|
||||||
|
function (next) {
|
||||||
|
process.stdout.write('\n git hash: ');
|
||||||
|
childProcess.execSync('git rev-parse HEAD', {
|
||||||
|
stdio: 'inherit',
|
||||||
|
});
|
||||||
|
next();
|
||||||
|
},
|
||||||
|
function (next) {
|
||||||
|
var config = require('../../config.json');
|
||||||
|
process.stdout.write('\n database: ' + config.database);
|
||||||
|
next();
|
||||||
|
},
|
||||||
|
db.init,
|
||||||
|
function (next) {
|
||||||
|
db.info(db.client, next);
|
||||||
|
},
|
||||||
|
function (info, next) {
|
||||||
|
process.stdout.write('\n version: ' + info.version);
|
||||||
|
process.stdout.write('\n engine: ' + info.storageEngine);
|
||||||
|
next();
|
||||||
|
},
|
||||||
|
], function (err) {
|
||||||
|
if (err) { throw err; }
|
||||||
|
process.exit();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.build = build.build;
|
||||||
|
exports.buildTargets = buildTargets;
|
||||||
|
exports.activate = activate;
|
||||||
|
exports.listPlugins = listPlugins;
|
||||||
|
exports.listEvents = listEvents;
|
||||||
|
exports.info = info;
|
@ -0,0 +1,15 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var path = require('path');
|
||||||
|
|
||||||
|
var baseDir = path.join(__dirname, '../../');
|
||||||
|
var loader = path.join(baseDir, 'loader.js');
|
||||||
|
var app = path.join(baseDir, 'app.js');
|
||||||
|
var pidfile = path.join(baseDir, 'pidfile');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
baseDir: baseDir,
|
||||||
|
loader: loader,
|
||||||
|
app: app,
|
||||||
|
pidfile: pidfile,
|
||||||
|
};
|
@ -0,0 +1,119 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var fs = require('fs');
|
||||||
|
var childProcess = require('child_process');
|
||||||
|
|
||||||
|
var fork = require('../meta/debugFork');
|
||||||
|
var paths = require('./paths');
|
||||||
|
|
||||||
|
var dirname = paths.baseDir;
|
||||||
|
|
||||||
|
function getRunningPid(callback) {
|
||||||
|
fs.readFile(paths.pidfile, {
|
||||||
|
encoding: 'utf-8',
|
||||||
|
}, function (err, pid) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
pid = parseInt(pid, 10);
|
||||||
|
|
||||||
|
try {
|
||||||
|
process.kill(pid, 0);
|
||||||
|
callback(null, pid);
|
||||||
|
} catch (e) {
|
||||||
|
callback(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function start(options) {
|
||||||
|
if (options.dev) {
|
||||||
|
process.env.NODE_ENV = 'development';
|
||||||
|
fork(paths.loader, ['--no-daemon', '--no-silent'], {
|
||||||
|
env: process.env,
|
||||||
|
cwd: dirname,
|
||||||
|
stdio: 'inherit',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (options.log) {
|
||||||
|
process.stdout.write('\nStarting NodeBB with logging output\n'.bold);
|
||||||
|
process.stdout.write('\nHit '.red + 'Ctrl-C '.bold + 'to exit'.red);
|
||||||
|
|
||||||
|
process.stdout.write('\nThe NodeBB process will continue to run in the background');
|
||||||
|
process.stdout.write('\nUse "' + './nodebb stop'.yellow + '" to stop the NodeBB server\n');
|
||||||
|
process.stdout.write('\n\n'.reset);
|
||||||
|
} else if (!options.silent) {
|
||||||
|
process.stdout.write('\nStarting NodeBB\n'.bold);
|
||||||
|
process.stdout.write(' "' + './nodebb stop'.yellow + '" to stop the NodeBB server\n');
|
||||||
|
process.stdout.write(' "' + './nodebb log'.yellow + '" to view server output\n');
|
||||||
|
process.stdout.write(' "' + './nodebb restart'.yellow + '" to restart NodeBB\n\n'.reset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Spawn a new NodeBB process
|
||||||
|
fork(paths.loader, process.argv.slice(3), {
|
||||||
|
env: process.env,
|
||||||
|
cwd: dirname,
|
||||||
|
});
|
||||||
|
if (options.log) {
|
||||||
|
childProcess.spawn('tail', ['-F', './logs/output.log'], {
|
||||||
|
cwd: dirname,
|
||||||
|
stdio: 'inherit',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function stop() {
|
||||||
|
getRunningPid(function (err, pid) {
|
||||||
|
if (!err) {
|
||||||
|
process.kill(pid, 'SIGTERM');
|
||||||
|
process.stdout.write('Stopping NodeBB. Goodbye!\n');
|
||||||
|
} else {
|
||||||
|
process.stdout.write('NodeBB is already stopped.\n');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function restart(options) {
|
||||||
|
getRunningPid(function (err, pid) {
|
||||||
|
if (!err) {
|
||||||
|
process.stdout.write('\nRestarting NodeBB\n'.bold);
|
||||||
|
process.kill(pid, 'SIGTERM');
|
||||||
|
|
||||||
|
options.silent = true;
|
||||||
|
start(options);
|
||||||
|
} else {
|
||||||
|
process.stdout.write('NodeBB could not be restarted, as a running instance could not be found.\n');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function status() {
|
||||||
|
getRunningPid(function (err, pid) {
|
||||||
|
if (!err) {
|
||||||
|
process.stdout.write('\nNodeBB Running '.bold + '(pid '.cyan + pid.toString().cyan + ')\n'.cyan);
|
||||||
|
process.stdout.write('\t"' + './nodebb stop'.yellow + '" to stop the NodeBB server\n');
|
||||||
|
process.stdout.write('\t"' + './nodebb log'.yellow + '" to view server output\n');
|
||||||
|
process.stdout.write('\t"' + './nodebb restart'.yellow + '" to restart NodeBB\n\n');
|
||||||
|
} else {
|
||||||
|
process.stdout.write('\nNodeBB is not running\n'.bold);
|
||||||
|
process.stdout.write('\t"' + './nodebb start'.yellow + '" to launch the NodeBB server\n\n'.reset);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function log() {
|
||||||
|
process.stdout.write('\nHit '.red + 'Ctrl-C '.bold + 'to exit'.red);
|
||||||
|
process.stdout.write('\n\n'.reset);
|
||||||
|
childProcess.spawn('tail', ['-F', './logs/output.log'], {
|
||||||
|
cwd: dirname,
|
||||||
|
stdio: 'inherit',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.start = start;
|
||||||
|
exports.stop = stop;
|
||||||
|
exports.restart = restart;
|
||||||
|
exports.status = status;
|
||||||
|
exports.log = log;
|
@ -0,0 +1,59 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var winston = require('winston');
|
||||||
|
var async = require('async');
|
||||||
|
|
||||||
|
var install = require('../../install/web').install;
|
||||||
|
|
||||||
|
function setup() {
|
||||||
|
var install = require('../install');
|
||||||
|
var build = require('../meta/build');
|
||||||
|
var prestart = require('../prestart');
|
||||||
|
|
||||||
|
winston.info('NodeBB Setup Triggered via Command Line');
|
||||||
|
|
||||||
|
process.stdout.write('\nWelcome to NodeBB!\n');
|
||||||
|
process.stdout.write('\nThis looks like a new installation, so you\'ll have to answer a few questions about your environment before we can proceed.\n');
|
||||||
|
process.stdout.write('Press enter to accept the default setting (shown in brackets).\n');
|
||||||
|
|
||||||
|
async.series([
|
||||||
|
install.setup,
|
||||||
|
prestart.loadConfig,
|
||||||
|
build.buildAll,
|
||||||
|
], function (err, data) {
|
||||||
|
// Disregard build step data
|
||||||
|
data = data[0];
|
||||||
|
|
||||||
|
var separator = ' ';
|
||||||
|
if (process.stdout.columns > 10) {
|
||||||
|
for (var x = 0, cols = process.stdout.columns - 10; x < cols; x += 1) {
|
||||||
|
separator += '=';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
process.stdout.write('\n' + separator + '\n\n');
|
||||||
|
|
||||||
|
if (err) {
|
||||||
|
winston.error('There was a problem completing NodeBB setup', err);
|
||||||
|
throw err;
|
||||||
|
} else {
|
||||||
|
if (data.hasOwnProperty('password')) {
|
||||||
|
process.stdout.write('An administrative user was automatically created for you:\n');
|
||||||
|
process.stdout.write(' Username: ' + data.username + '\n');
|
||||||
|
process.stdout.write(' Password: ' + data.password + '\n');
|
||||||
|
process.stdout.write('\n');
|
||||||
|
}
|
||||||
|
process.stdout.write('NodeBB Setup Completed. Run \'./nodebb start\' to manually start your NodeBB server.\n');
|
||||||
|
|
||||||
|
// If I am a child process, notify the parent of the returned data before exiting (useful for notifying
|
||||||
|
// hosts of auto-generated username/password during headless setups)
|
||||||
|
if (process.send) {
|
||||||
|
process.send(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
process.exit();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.setup = setup;
|
||||||
|
exports.webInstall = install;
|
@ -0,0 +1,216 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var async = require('async');
|
||||||
|
var prompt = require('prompt');
|
||||||
|
var request = require('request');
|
||||||
|
var cproc = require('child_process');
|
||||||
|
var semver = require('semver');
|
||||||
|
var fs = require('fs');
|
||||||
|
var path = require('path');
|
||||||
|
|
||||||
|
var paths = require('./paths');
|
||||||
|
|
||||||
|
var dirname = paths.baseDir;
|
||||||
|
|
||||||
|
function getModuleVersions(modules, callback) {
|
||||||
|
var versionHash = {};
|
||||||
|
|
||||||
|
async.eachLimit(modules, 50, function (module, next) {
|
||||||
|
fs.readFile(path.join(dirname, 'node_modules', module, 'package.json'), { encoding: 'utf-8' }, function (err, pkg) {
|
||||||
|
if (err) {
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
pkg = JSON.parse(pkg);
|
||||||
|
versionHash[module] = pkg.version;
|
||||||
|
next();
|
||||||
|
} catch (err) {
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}, function (err) {
|
||||||
|
callback(err, versionHash);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getInstalledPlugins(callback) {
|
||||||
|
async.parallel({
|
||||||
|
files: async.apply(fs.readdir, path.join(dirname, 'node_modules')),
|
||||||
|
deps: async.apply(fs.readFile, path.join(dirname, 'package.json'), { encoding: 'utf-8' }),
|
||||||
|
}, function (err, payload) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
var isNbbModule = /^nodebb-(?:plugin|theme|widget|rewards)-[\w-]+$/;
|
||||||
|
var moduleName;
|
||||||
|
var isGitRepo;
|
||||||
|
|
||||||
|
payload.files = payload.files.filter(function (file) {
|
||||||
|
return isNbbModule.test(file);
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
payload.deps = JSON.parse(payload.deps).dependencies;
|
||||||
|
payload.bundled = [];
|
||||||
|
payload.installed = [];
|
||||||
|
} catch (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (moduleName in payload.deps) {
|
||||||
|
if (isNbbModule.test(moduleName)) {
|
||||||
|
payload.bundled.push(moduleName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Whittle down deps to send back only extraneously installed plugins/themes/etc
|
||||||
|
payload.files.forEach(function (moduleName) {
|
||||||
|
try {
|
||||||
|
fs.accessSync(path.join(dirname, 'node_modules', moduleName, '.git'));
|
||||||
|
isGitRepo = true;
|
||||||
|
} catch (e) {
|
||||||
|
isGitRepo = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
payload.files.indexOf(moduleName) !== -1 && // found in `node_modules/`
|
||||||
|
payload.bundled.indexOf(moduleName) === -1 && // not found in `package.json`
|
||||||
|
!fs.lstatSync(path.join(dirname, 'node_modules', moduleName)).isSymbolicLink() && // is not a symlink
|
||||||
|
!isGitRepo // .git/ does not exist, so it is not a git repository
|
||||||
|
) {
|
||||||
|
payload.installed.push(moduleName);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
getModuleVersions(payload.installed, callback);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCurrentVersion(callback) {
|
||||||
|
fs.readFile(path.join(dirname, 'package.json'), { encoding: 'utf-8' }, function (err, pkg) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
pkg = JSON.parse(pkg);
|
||||||
|
} catch (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
callback(null, pkg.version);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkPlugins(standalone, callback) {
|
||||||
|
if (standalone) {
|
||||||
|
process.stdout.write('Checking installed plugins and themes for updates... ');
|
||||||
|
}
|
||||||
|
|
||||||
|
async.waterfall([
|
||||||
|
async.apply(async.parallel, {
|
||||||
|
plugins: async.apply(getInstalledPlugins),
|
||||||
|
version: async.apply(getCurrentVersion),
|
||||||
|
}),
|
||||||
|
function (payload, next) {
|
||||||
|
var toCheck = Object.keys(payload.plugins);
|
||||||
|
|
||||||
|
if (!toCheck.length) {
|
||||||
|
process.stdout.write('OK'.green + '\n'.reset);
|
||||||
|
return next(null, []); // no extraneous plugins installed
|
||||||
|
}
|
||||||
|
|
||||||
|
request({
|
||||||
|
method: 'GET',
|
||||||
|
url: 'https://packages.nodebb.org/api/v1/suggest?version=' + payload.version + '&package[]=' + toCheck.join('&package[]='),
|
||||||
|
json: true,
|
||||||
|
}, function (err, res, body) {
|
||||||
|
if (err) {
|
||||||
|
process.stdout.write('error'.red + '\n'.reset);
|
||||||
|
return next(err);
|
||||||
|
}
|
||||||
|
process.stdout.write('OK'.green + '\n'.reset);
|
||||||
|
|
||||||
|
if (!Array.isArray(body) && toCheck.length === 1) {
|
||||||
|
body = [body];
|
||||||
|
}
|
||||||
|
|
||||||
|
var current;
|
||||||
|
var suggested;
|
||||||
|
var upgradable = body.map(function (suggestObj) {
|
||||||
|
current = payload.plugins[suggestObj.package];
|
||||||
|
suggested = suggestObj.version;
|
||||||
|
|
||||||
|
if (suggestObj.code === 'match-found' && semver.gt(suggested, current)) {
|
||||||
|
return {
|
||||||
|
name: suggestObj.package,
|
||||||
|
current: current,
|
||||||
|
suggested: suggested,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}).filter(Boolean);
|
||||||
|
|
||||||
|
next(null, upgradable);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
], callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
function upgradePlugins(callback) {
|
||||||
|
var standalone = false;
|
||||||
|
if (typeof callback !== 'function') {
|
||||||
|
callback = function () {};
|
||||||
|
standalone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkPlugins(standalone, function (err, found) {
|
||||||
|
if (err) {
|
||||||
|
process.stdout.write('Warning'.yellow + ': An unexpected error occured when attempting to verify plugin upgradability\n'.reset);
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found && found.length) {
|
||||||
|
process.stdout.write('\nA total of ' + String(found.length).bold + ' package(s) can be upgraded:\n');
|
||||||
|
found.forEach(function (suggestObj) {
|
||||||
|
process.stdout.write(' * '.yellow + suggestObj.name.reset + ' (' + suggestObj.current.yellow + ' -> '.reset + suggestObj.suggested.green + ')\n'.reset);
|
||||||
|
});
|
||||||
|
process.stdout.write('\n');
|
||||||
|
} else {
|
||||||
|
if (standalone) {
|
||||||
|
process.stdout.write('\nAll packages up-to-date!'.green + '\n'.reset);
|
||||||
|
}
|
||||||
|
return callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
prompt.message = '';
|
||||||
|
prompt.delimiter = '';
|
||||||
|
|
||||||
|
prompt.start();
|
||||||
|
prompt.get({
|
||||||
|
name: 'upgrade',
|
||||||
|
description: 'Proceed with upgrade (y|n)?'.reset,
|
||||||
|
type: 'string',
|
||||||
|
}, function (err, result) {
|
||||||
|
if (err) {
|
||||||
|
return callback(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (['y', 'Y', 'yes', 'YES'].indexOf(result.upgrade) !== -1) {
|
||||||
|
process.stdout.write('\nUpgrading packages...');
|
||||||
|
var args = ['i'];
|
||||||
|
found.forEach(function (suggestObj) {
|
||||||
|
args.push(suggestObj.name + '@' + suggestObj.suggested);
|
||||||
|
});
|
||||||
|
|
||||||
|
cproc.execFile((process.platform === 'win32') ? 'npm.cmd' : 'npm', args, { stdio: 'ignore' }, callback);
|
||||||
|
} else {
|
||||||
|
process.stdout.write('\nPackage upgrades skipped'.yellow + '. Check for upgrades at any time by running "'.reset + './nodebb upgrade-plugins'.green + '".\n'.reset);
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.upgradePlugins = upgradePlugins;
|
@ -0,0 +1,117 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var async = require('async');
|
||||||
|
var nconf = require('nconf');
|
||||||
|
|
||||||
|
var packageInstall = require('../meta/package-install');
|
||||||
|
var upgrade = require('../upgrade');
|
||||||
|
var build = require('../meta/build');
|
||||||
|
var db = require('../database');
|
||||||
|
var meta = require('../meta');
|
||||||
|
var upgradePlugins = require('./upgrade-plugins').upgradePlugins;
|
||||||
|
|
||||||
|
var steps = {
|
||||||
|
package: function (next) {
|
||||||
|
process.stdout.write('Updating package.json file with defaults... \n'.yellow);
|
||||||
|
packageInstall.updatePackageFile();
|
||||||
|
packageInstall.preserveExtraneousPlugins();
|
||||||
|
process.stdout.write('OK\n'.green);
|
||||||
|
next();
|
||||||
|
},
|
||||||
|
install: function (next) {
|
||||||
|
process.stdout.write('Bringing base dependencies up to date... \n'.yellow);
|
||||||
|
packageInstall.npmInstallProduction();
|
||||||
|
process.stdout.write('OK\n'.green);
|
||||||
|
next();
|
||||||
|
},
|
||||||
|
plugins: function (next) {
|
||||||
|
process.stdout.write('Checking installed plugins for updates... \n'.yellow);
|
||||||
|
async.series([
|
||||||
|
db.init,
|
||||||
|
upgradePlugins,
|
||||||
|
function (next) {
|
||||||
|
process.stdout.write('OK\n'.green);
|
||||||
|
next();
|
||||||
|
},
|
||||||
|
], next);
|
||||||
|
},
|
||||||
|
schema: function (next) {
|
||||||
|
process.stdout.write('Updating NodeBB data store schema...\n'.yellow);
|
||||||
|
async.series([
|
||||||
|
db.init,
|
||||||
|
upgrade.run,
|
||||||
|
function (next) {
|
||||||
|
process.stdout.write('OK\n'.green);
|
||||||
|
next();
|
||||||
|
},
|
||||||
|
], next);
|
||||||
|
},
|
||||||
|
build: function (next) {
|
||||||
|
process.stdout.write('Rebuilding assets...\n'.yellow);
|
||||||
|
async.series([
|
||||||
|
build.buildAll,
|
||||||
|
function (next) {
|
||||||
|
process.stdout.write('OK\n'.green);
|
||||||
|
next();
|
||||||
|
},
|
||||||
|
], next);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function runSteps(tasks) {
|
||||||
|
tasks = tasks.map(function (key, i) {
|
||||||
|
return function (next) {
|
||||||
|
process.stdout.write(((i + 1) + '. ').bold);
|
||||||
|
return steps[key](next);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
async.series(tasks, function (err) {
|
||||||
|
if (err) {
|
||||||
|
process.stdout.write('Error occurred during upgrade');
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
var message = 'NodeBB Upgrade Complete!';
|
||||||
|
// some consoles will return undefined/zero columns, so just use 2 spaces in upgrade script if we can't get our column count
|
||||||
|
var columns = process.stdout.columns;
|
||||||
|
var spaces = columns ? new Array(Math.floor(columns / 2) - (message.length / 2) + 1).join(' ') : ' ';
|
||||||
|
|
||||||
|
process.stdout.write('\n' + spaces + message.green.bold + '\n\n'.reset);
|
||||||
|
|
||||||
|
process.exit();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function runUpgrade(upgrades, options) {
|
||||||
|
process.stdout.write('\nUpdating NodeBB...\n'.cyan);
|
||||||
|
|
||||||
|
// disable mongo timeouts during upgrade
|
||||||
|
nconf.set('mongo:options:socketTimeoutMS', 0);
|
||||||
|
|
||||||
|
if (upgrades === true) {
|
||||||
|
var tasks = Object.keys(steps);
|
||||||
|
if (options.package || options.install ||
|
||||||
|
options.plugins || options.schema || options.build) {
|
||||||
|
tasks = tasks.filter(function (key) {
|
||||||
|
return options[key];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
runSteps(tasks);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
async.series([
|
||||||
|
db.init,
|
||||||
|
meta.configs.init,
|
||||||
|
async.apply(upgrade.runParticular, upgrades),
|
||||||
|
], function (err) {
|
||||||
|
if (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.upgrade = runUpgrade;
|
@ -0,0 +1,84 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
var nconf = require('nconf');
|
||||||
|
var url = require('url');
|
||||||
|
var winston = require('winston');
|
||||||
|
var path = require('path');
|
||||||
|
|
||||||
|
var pkg = require('../package.json');
|
||||||
|
var dirname = require('./cli/paths').baseDir;
|
||||||
|
|
||||||
|
function setupWinston() {
|
||||||
|
winston.remove(winston.transports.Console);
|
||||||
|
winston.add(winston.transports.Console, {
|
||||||
|
colorize: true,
|
||||||
|
timestamp: function () {
|
||||||
|
var date = new Date();
|
||||||
|
return nconf.get('json-logging') ? date.toJSON() :
|
||||||
|
date.getDate() + '/' + (date.getMonth() + 1) + ' ' +
|
||||||
|
date.toTimeString().substr(0, 8) + ' [' + global.process.pid + ']';
|
||||||
|
},
|
||||||
|
level: nconf.get('log-level') || (global.env === 'production' ? 'info' : 'verbose'),
|
||||||
|
json: !!nconf.get('json-logging'),
|
||||||
|
stringify: !!nconf.get('json-logging'),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadConfig(configFile) {
|
||||||
|
winston.verbose('* using configuration stored in: %s', configFile);
|
||||||
|
|
||||||
|
nconf.file({
|
||||||
|
file: configFile,
|
||||||
|
});
|
||||||
|
|
||||||
|
nconf.defaults({
|
||||||
|
base_dir: dirname,
|
||||||
|
themes_path: path.join(dirname, 'node_modules'),
|
||||||
|
upload_path: 'public/uploads',
|
||||||
|
views_dir: path.join(dirname, 'build/public/templates'),
|
||||||
|
version: pkg.version,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!nconf.get('isCluster')) {
|
||||||
|
nconf.set('isPrimary', 'true');
|
||||||
|
nconf.set('isCluster', 'false');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure themes_path is a full filepath
|
||||||
|
nconf.set('themes_path', path.resolve(dirname, nconf.get('themes_path')));
|
||||||
|
nconf.set('core_templates_path', path.join(dirname, 'src/views'));
|
||||||
|
nconf.set('base_templates_path', path.join(nconf.get('themes_path'), 'nodebb-theme-persona/templates'));
|
||||||
|
|
||||||
|
nconf.set('upload_path', path.resolve(nconf.get('base_dir'), nconf.get('upload_path')));
|
||||||
|
|
||||||
|
if (nconf.get('url')) {
|
||||||
|
nconf.set('url_parsed', url.parse(nconf.get('url')));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Explicitly cast 'jobsDisabled' as Bool
|
||||||
|
var castAsBool = ['jobsDisabled'];
|
||||||
|
nconf.stores.env.readOnly = false;
|
||||||
|
castAsBool.forEach(function (prop) {
|
||||||
|
var value = nconf.get(prop);
|
||||||
|
if (value) {
|
||||||
|
nconf.set(prop, typeof value === 'boolean' ? value : String(value).toLowerCase() === 'true');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
nconf.stores.env.readOnly = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function versionCheck() {
|
||||||
|
var version = process.version.slice(1);
|
||||||
|
var range = pkg.engines.node;
|
||||||
|
var semver = require('semver');
|
||||||
|
var compatible = semver.satisfies(version, range);
|
||||||
|
|
||||||
|
if (!compatible) {
|
||||||
|
winston.warn('Your version of Node.js is too outdated for NodeBB. Please update your version of Node.js.');
|
||||||
|
winston.warn('Recommended ' + range.green + ', '.reset + version.yellow + ' provided\n'.reset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.setupWinston = setupWinston;
|
||||||
|
exports.loadConfig = loadConfig;
|
||||||
|
exports.versionCheck = versionCheck;
|
Loading…
Reference in New Issue