From 553567c3b2601eca943f25e67bd339a394cdba68 Mon Sep 17 00:00:00 2001 From: Peter Jaszkowiak Date: Thu, 2 Feb 2017 19:15:01 -0700 Subject: [PATCH] Refactor `nodebb`, move `build.js`, add `--dev` --- app.js | 8 +- nodebb | 783 ++++++++++++++++++---------------- package.json | 2 +- build.js => src/meta/build.js | 8 +- src/socket.io/admin.js | 2 +- test/mocks/databasemock.js | 2 +- 6 files changed, 430 insertions(+), 375 deletions(-) rename build.js => src/meta/build.js (95%) diff --git a/app.js b/app.js index b6d7d07829..8844d8af6f 100644 --- a/app.js +++ b/app.js @@ -75,7 +75,7 @@ if (nconf.get('setup') || nconf.get('install')) { } else if (nconf.get('reset')) { async.waterfall([ async.apply(require('./src/reset').reset), - async.apply(require('./build').buildAll) + async.apply(require('./src/meta/build').buildAll) ], function (err) { process.exit(err ? 1 : 0); }); @@ -84,7 +84,7 @@ if (nconf.get('setup') || nconf.get('install')) { } else if (nconf.get('plugins')) { listPlugins(); } else if (nconf.get('build')) { - require('./build').build(nconf.get('build')); + require('./src/meta/build').build(nconf.get('build')); } else { require('./src/start').start(); } @@ -126,7 +126,7 @@ function setup() { winston.info('NodeBB Setup Triggered via Command Line'); var install = require('./src/install'); - var build = require('./build'); + var build = require('./src/meta/build'); 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'); @@ -174,7 +174,7 @@ function upgrade() { var db = require('./src/database'); var meta = require('./src/meta'); var upgrade = require('./src/upgrade'); - var build = require('./build'); + var build = require('./src/meta/build'); async.series([ async.apply(db.init), diff --git a/nodebb b/nodebb index e1a4ab7fbf..dff44fc5af 100755 --- a/nodebb +++ b/nodebb @@ -1,15 +1,17 @@ #!/usr/bin/env node +'use strict'; + try { - var colors = require('colors'), - cproc = require('child_process'), - argv = require('minimist')(process.argv.slice(2)), - fs = require('fs'), - path = require('path'), - request = require('request'), - semver = require('semver'), - prompt = require('prompt'), - async = require('async'); + require('colors'); + var cproc = require('child_process'); + var args = require('minimist')(process.argv.slice(2)); + var fs = require('fs'); + var path = require('path'); + var request = require('request'); + var semver = require('semver'); + var prompt = require('prompt'); + var async = require('async'); } catch (e) { if (e.code === 'MODULE_NOT_FOUND') { process.stdout.write('NodeBB could not be started because it\'s dependencies have not been installed.\n'); @@ -21,407 +23,460 @@ try { } } -var getRunningPid = function (callback) { - fs.readFile(__dirname + '/pidfile', { - encoding: 'utf-8' - }, function (err, pid) { - if (err) { - return callback(err); +if (args.dev) { + process.env.NODE_ENV = 'development'; +} + +function getRunningPid(callback) { + fs.readFile(__dirname + '/pidfile', { + encoding: 'utf-8' + }, function (err, pid) { + if (err) { + return callback(err); + } + + try { + process.kill(parseInt(pid, 10), 0); + callback(null, parseInt(pid, 10)); + } catch(e) { + callback(e); + } + }); +} +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); + return callback(null, pkg.version); + } catch(err) { + return callback(err); + } + }); +} +function fork(args) { + return cproc.fork('app.js', args, { + cwd: __dirname, + silent: false + }); +} +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\-]+$/, + moduleName, 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 { - process.kill(parseInt(pid, 10), 0); - callback(null, parseInt(pid, 10)); + fs.accessSync(path.join(__dirname, 'node_modules/' + moduleName, '.git')); + isGitRepo = true; } catch(e) { - callback(e); - } - }); - }, - getCurrentVersion = function (callback) { - fs.readFile(path.join(__dirname, 'package.json'), { encoding: 'utf-8' }, function (err, pkg) { - if (err) { - return callback(err); + isGitRepo = false; } - try { - pkg = JSON.parse(pkg); - return callback(null, pkg.version); - } catch(err) { - return callback(err); + 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); } }); - }, - fork = function (args) { - cproc.fork('app.js', args, { - cwd: __dirname, - silent: false - }); - }, - getInstalledPlugins = function (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\-]+$/, - moduleName, isGitRepo; + getModuleVersions(payload.installed, callback); + }); +} +function getModuleVersions(modules, callback) { + var versionHash = {}; - payload.files = payload.files.filter(function (file) { - return isNbbModule.test(file); - }); + 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 { - payload.deps = JSON.parse(payload.deps).dependencies; - payload.bundled = []; - payload.installed = []; + pkg = JSON.parse(pkg); + versionHash[module] = pkg.version; + next(); } catch (err) { - return callback(err); + next(err); } + }); + }, function (err) { + callback(err, versionHash); + }); +} +function checkPlugins(standalone, callback) { + if (standalone) { + process.stdout.write('Checking installed plugins and themes for updates... '); + } - for (moduleName in payload.deps) { - if (isNbbModule.test(moduleName)) { - payload.bundled.push(moduleName); - } + 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 } - // 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); - }); - }, - getModuleVersions = function (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) { + 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); - try { - pkg = JSON.parse(pkg); - versionHash[module] = pkg.version; - next(); - } catch (err) { - next(err); + if (!Array.isArray(body) && toCheck.length === 1) { + body = [body]; } + + var current, suggested, + 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 + }; + } else { + return null; + } + }).filter(Boolean); + + next(null, upgradable); }); - }, function (err) { - callback(err, versionHash); - }); - }, - checkPlugins = function (standalone, callback) { - if (standalone) { - process.stdout.write('Checking installed plugins and themes for updates... '); } + ], callback); +} +function upgradePlugins(callback) { + var standalone = false; + if (typeof callback !== 'function') { + callback = function () {}; + standalone = true; + } - 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 - } + 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); + } - 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 (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(); + } - if (!Array.isArray(body) && toCheck.length === 1) { - body = [body]; - } + prompt.message = ''; + prompt.delimiter = ''; - var current, suggested, - 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 - }; - } else { - return null; - } - }).filter(Boolean); - - next(null, upgradable); - }); - } - ], callback); - }, - upgradePlugins = function (callback) { - var standalone = false; - if (typeof callback !== 'function') { - callback = function () {}; - standalone = true; - }; - - checkPlugins(standalone, function (err, found) { + prompt.start(); + prompt.get({ + name: 'upgrade', + description: 'Proceed with upgrade (y|n)?'.reset, + type: 'string' + }, function (err, result) { 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'); + if (['y', 'Y', 'yes', 'YES'].indexOf(result.upgrade) !== -1) { + process.stdout.write('\nUpgrading packages...'); + var args = ['npm', 'i']; found.forEach(function (suggestObj) { - process.stdout.write(' * '.yellow + suggestObj.name.reset + ' (' + suggestObj.current.yellow + ' -> '.reset + suggestObj.suggested.green + ')\n'.reset); + args.push(suggestObj.name + '@' + suggestObj.suggested); + }); + + require('child_process').execFile('/usr/bin/env', args, { stdio: 'ignore' }, function (err) { + if (!err) { + process.stdout.write(' OK\n'.green); + } + + callback(err); }); - process.stdout.write('\n'); } else { - if (standalone) { - process.stdout.write('\nAll packages up-to-date!'.green + '\n'.reset); - } - return callback(); + process.stdout.write('\nPackage upgrades skipped'.yellow + '. Check for upgrades at any time by running "'.reset + './nodebb upgrade-plugins'.green + '".\n'.reset); + 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); +var commands = { + status: { + description: 'View the status of the NodeBB server', + usage: 'Usage: ' + './nodebb status'.yellow, + handler: function () { + 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); } - - if (['y', 'Y', 'yes', 'YES'].indexOf(result.upgrade) !== -1) { - process.stdout.write('\nUpgrading packages...'); - var args = ['npm', 'i']; - found.forEach(function (suggestObj) { - args.push(suggestObj.name + '@' + suggestObj.suggested); - }); - - require('child_process').execFile('/usr/bin/env', args, { stdio: 'ignore' }, function (err) { - if (!err) { - process.stdout.write(' OK\n'.green); - } - - callback(err); - }); + }); + }, + }, + start: { + description: 'Start the NodeBB server', + usage: 'Usage: ' + './nodebb start'.yellow, + handler: function () { + 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 + cproc.fork(__dirname + '/loader.js', { + env: process.env + }); + }, + }, + stop: { + description: 'Stop the NodeBB server', + usage: 'Usage: ' + './nodebb stop'.yellow, + handler: function () { + getRunningPid(function (err, pid) { + if (!err) { + process.kill(pid, 'SIGTERM'); + process.stdout.write('Stopping NodeBB. Goodbye!\n'); } else { - process.stdout.write('\nPackage upgrades skipped'.yellow + '. Check for upgrades at any time by running "'.reset + './nodebb upgrade-plugins'.green + '".\n'.reset); - callback(); + process.stdout.write('NodeBB is already stopped.\n'); } }); - }); - }; - -switch(process.argv[2]) { - case '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); - } - }); - break; - - case 'start': - 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 - cproc.fork(__dirname + '/loader.js', { - env: process.env - }); - break; - - case 'slog': - process.stdout.write('\nStarting NodeBB with logging output\n'.bold); - process.stdout.write('\nHit '.red + 'Ctrl-C '.bold + 'to exit'.red); - process.stdout.write('\n\n'.reset); - - // Spawn a new NodeBB process - cproc.fork(__dirname + '/loader.js', { - env: process.env - }); - cproc.spawn('tail', ['-F', './logs/output.log'], { - cwd: __dirname, - stdio: 'inherit' - }); - break; - - case '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'); - } - }); - break; - - case 'restart': - getRunningPid(function (err, pid) { - if (!err) { - process.kill(pid, 'SIGHUP'); - process.stdout.write('\nRestarting NodeBB\n'.bold); - } else { - process.stdout.write('NodeBB could not be restarted, as a running instance could not be found.\n'); - } - }); - break; + }, + }, + restart: { + description: 'Restart the NodeBB server', + usage: 'Usage: ' + './nodebb restart'.yellow, + handler: function () { + getRunningPid(function (err, pid) { + if (!err) { + process.kill(pid, 'SIGHUP'); + process.stdout.write('\nRestarting NodeBB\n'.bold); + } else { + process.stdout.write('NodeBB could not be restarted, as a running instance could not be found.\n'); + } + }); + }, + }, + log: { + description: 'Open the output log (useful for debugging)', + usage: 'Usage: ' + './nodebb log'.yellow, + handler: function () { + process.stdout.write('\nHit '.red + 'Ctrl-C '.bold + 'to exit'.red); + process.stdout.write('\n\n'.reset); + cproc.spawn('tail', ['-F', './logs/output.log'], { + cwd: __dirname, + stdio: 'inherit' + }); + }, + }, + slog: { + description: 'Start the NodeBB server and view the live output log', + usage: 'Usage: ' + './nodebb slog'.yellow, + handler: function () { + process.stdout.write('\nStarting NodeBB with logging output\n'.bold); + process.stdout.write('\nHit '.red + 'Ctrl-C '.bold + 'to exit'.red); + process.stdout.write('\n\n'.reset); + + // Spawn a new NodeBB process + cproc.fork(__dirname + '/loader.js', { + env: process.env + }); + cproc.spawn('tail', ['-F', './logs/output.log'], { + cwd: __dirname, + stdio: 'inherit' + }); + }, + }, + dev: { + description: 'Start NodeBB in verbose development mode', + usage: 'Usage: ' + './nodebb dev'.yellow, + handler: function () { + process.env.NODE_ENV = 'development'; + cproc.fork(__dirname + '/loader.js', ['--no-daemon', '--no-silent'], { + env: process.env + }); + }, + }, + build: { + description: 'Compile static assets (CSS, Javascript, etc)', + usage: 'Usage: ' + './nodebb build'.yellow + ' [js,clientCSS,acpCSS,tpl,lang]'.red + '\n' + + ' e.g. ' + './nodebb build js,tpl'.yellow + '\tbuilds JS and templates\n' + + ' ' + './nodebb build'.yellow + '\t\tbuilds all targets\n', + handler: function () { + var arr = ['--build'].concat(process.argv.slice(3)); + fork(arr); + }, + }, + setup: { + description: 'Run the NodeBB setup script', + usage: 'Usage: ' + './nodebb setup'.yellow, + handler: function () { + var arr = ['--setup'].concat(process.argv.slice(3)); + fork(arr); + }, + }, + reset: { + description: 'Disable plugins and restore the default theme', + usage: 'Usage: ' + './nodebb reset '.yellow + '{-t|-p|-w|-s|-a}'.red + '\n' + + ' -t \tuse specified theme\n' + + ' -p \tdisable specified plugin\n' + + '\n' + + ' -t\t\tuse default theme\n' + + ' -p\t\tdisable all but core plugins\n' + + ' -w\t\twidgets\n' + + ' -s\t\tsettings\n' + + ' -a\t\tall of the above\n', + handler: function () { + var arr = ['--reset'].concat(process.argv.slice(3)); + fork(arr); + }, + }, + activate: { + description: 'Activate a plugin for the next startup of NodeBB', + usage: 'Usage: ' + './nodebb activate '.yellow, + handler: function () { + var arr = ['--activate=' + args._[1]].concat(process.argv.slice(4)); + fork(arr); + }, + }, + plugins: { + description: 'List all installed plugins', + usage: 'Usage: ' + './nodebb plugins'.yellow, + handler: function () { + var arr = ['--plugins'].concat(process.argv.slice(3)); + fork(arr); + }, + }, + upgrade: { + description: 'Run NodeBB upgrade scripts, ensure packages are up-to-date', + usage: 'Usage: ' + './nodebb upgrade'.yellow, + handler: function () { + async.series([ + function (next) { + process.stdout.write('1. '.bold + 'Bringing base dependencies up to date... '.yellow); + cproc.exec('npm i --production', { cwd: __dirname, stdio: 'ignore' }, next); + }, + function (next) { + process.stdout.write('OK\n'.green); + process.stdout.write('2. '.bold + 'Checking installed plugins for updates... '.yellow); + upgradePlugins(next); + }, + function (next) { + process.stdout.write('3. '.bold + 'Updating NodeBB data store schema...\n'.yellow); + var arr = ['--upgrade'].concat(process.argv.slice(3)); + var upgradeProc = fork(arr); + + upgradeProc.on('close', next); + } + ], function (err) { + if (err) { + process.stdout.write('\nError'.red + ': ' + err.message + '\n'); + } else { + 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(' ') : " "; - case 'reload': - getRunningPid(function (err, pid) { - if (!err) { - process.kill(pid, 'SIGUSR2'); - } else { - process.stdout.write('NodeBB could not be reloaded, as a running instance could not be found.\n'); + process.stdout.write('OK\n'.green); + process.stdout.write('\n' + spaces + message.green.bold + '\n\n'.reset); + } + }); + }, + }, + upgradePlugins: { + hidden: true, + description: '', + handler: function () { + upgradePlugins(); + }, + }, + help: { + description: 'Display the help message for a given command', + usage: 'Usage: ' + './nodebb help '.yellow, + handler: function () { + var command = commands[args._[1]]; + if (command) { + process.stdout.write(command.description + '\n'.reset); + process.stdout.write(command.usage + '\n'.reset); + + return; } - }); - break; - - case 'dev': - process.env.NODE_ENV = 'development'; - cproc.fork(__dirname + '/loader.js', ['--no-daemon', '--no-silent'], { - env: process.env - }); - break; - - case 'log': - process.stdout.write('\nHit '.red + 'Ctrl-C '.bold + 'to exit'.red); - process.stdout.write('\n\n'.reset); - cproc.spawn('tail', ['-F', './logs/output.log'], { - cwd: __dirname, - stdio: 'inherit' - }); - break; + var keys = Object.keys(commands).filter(function (key) { + return !commands[key].hidden; + }); - case 'build': - var args = process.argv.slice(0); - args[2] = '--' + args[2]; + process.stdout.write('\nWelcome to NodeBB\n\n'.bold); + process.stdout.write('Usage: ./nodebb {' + keys.join('|') + '}\n\n'); - fork(args); - break; + var usage = keys.map(function (key) { + var line = '\t' + key.yellow + (key.length < 8 ? '\t\t' : '\t'); + return line + commands[key].description; + }).join('\n'); - case 'setup': - cproc.fork('app.js', ['--setup'], { - cwd: __dirname, - silent: false - }); - break; - - case 'reset': - var args = process.argv.slice(0); - args.unshift('--reset'); - fork(args); - break; - - case 'activate': - var args = process.argv.slice(0); - args.unshift('--activate=' + process.argv[3]); - fork(args); - break; - - case 'plugins': - var args = process.argv.slice(0); - args.unshift('--plugins'); - fork(args); - break; - - case 'upgrade-plugins': - upgradePlugins(); - break; - - case 'upgrade': - async.series([ - function (next) { - process.stdout.write('1. '.bold + 'Bringing base dependencies up to date... '.yellow); - cproc.exec('npm i --production', { cwd: __dirname, stdio: 'ignore' }, next); - }, - function (next) { - process.stdout.write('OK\n'.green); - process.stdout.write('2. '.bold + 'Checking installed plugins for updates... '.yellow); - upgradePlugins(next); - }, - function (next) { - process.stdout.write('3. '.bold + 'Updating NodeBB data store schema...\n'.yellow); - var upgradeProc = cproc.fork('app.js', ['--upgrade'], { - cwd: __dirname, - silent: false - }); + process.stdout.write(usage + '\n'.reset); + }, + }, +}; - upgradeProc.on('close', next); - } - ], function (err) { - if (err) { - process.stdout.write('\nError'.red + ': ' + err.message + '\n'); - } else { - 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(' ') : " "; +commands['upgrade-plugins'] = commands.upgradePlugins; - process.stdout.write('OK\n'.green); - process.stdout.write('\n' + spaces + message.green.bold + '\n\n'.reset); - } - }); - break; - - default: - process.stdout.write('\nWelcome to NodeBB\n\n'.bold); - process.stdout.write('Usage: ./nodebb {start|slog|stop|reload|restart|log|build|setup|reset|upgrade|dev}\n\n'); - process.stdout.write('\t' + 'start'.yellow + '\t\tStart the NodeBB server\n'); - process.stdout.write('\t' + 'slog'.yellow + '\t\tStarts the NodeBB server and displays the live output log\n'); - process.stdout.write('\t' + 'stop'.yellow + '\t\tStops the NodeBB server\n'); - process.stdout.write('\t' + 'reload'.yellow + '\t\tRestarts NodeBB\n'); - process.stdout.write('\t' + 'restart'.yellow + '\t\tRestarts NodeBB\n'); - process.stdout.write('\t' + 'log'.yellow + '\t\tOpens the logging interface (useful for debugging)\n'); - process.stdout.write('\t' + 'build'.yellow + '\t\tCompiles javascript, css stylesheets, and templates\n'); - process.stdout.write('\t' + 'setup'.yellow + '\t\tRuns the NodeBB setup script\n'); - process.stdout.write('\t' + 'reset'.yellow + '\t\tDisables all plugins, restores the default theme.\n'); - process.stdout.write('\t' + 'activate'.yellow + '\tActivates a plugin for the next startup of NodeBB.\n'); - process.stdout.write('\t' + 'plugins'.yellow + '\t\tList all plugins that have been installed.\n'); - process.stdout.write('\t' + 'upgrade'.yellow + '\t\tRun NodeBB upgrade scripts, ensure packages are up-to-date\n'); - process.stdout.write('\t' + 'dev'.yellow + '\t\tStart NodeBB in interactive development mode\n'); - process.stdout.write('\n'.reset); - break; +if (!commands[args._[0]]) { + commands.help.handler(); +} else { + commands[args._[0]].handler(); } diff --git a/package.json b/package.json index e0419bc58f..fa0d658065 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "scripts": { "start": "node loader.js", "lint": "eslint --cache .", - "pretest": "npm run lint", + "pretest": "npm run lint && node app --build", "test": "istanbul cover node_modules/mocha/bin/_mocha -- -R dot", "coveralls": "istanbul cover _mocha --report lcovonly -- -R dot && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage" }, diff --git a/build.js b/src/meta/build.js similarity index 95% rename from build.js rename to src/meta/build.js index a0250dfb37..20d0d8eec4 100644 --- a/build.js +++ b/src/meta/build.js @@ -14,9 +14,9 @@ exports.buildAll = function (callback) { exports.build = function build(targets, callback) { buildStart = Date.now(); - var db = require('./src/database'); - var meta = require('./src/meta'); - var plugins = require('./src/plugins'); + var db = require('../database'); + var meta = require('../meta'); + var plugins = require('../plugins'); targets = (targets === true ? valid : targets.split(',').filter(function (target) { @@ -43,7 +43,7 @@ exports.build = function build(targets, callback) { }; exports.buildTargets = function (targets, callback) { - var meta = require('./src/meta'); + var meta = require('../meta'); buildStart = buildStart || Date.now(); var step = function (startTime, target, next) { diff --git a/src/socket.io/admin.js b/src/socket.io/admin.js index b16bafa296..987f607ec9 100644 --- a/src/socket.io/admin.js +++ b/src/socket.io/admin.js @@ -57,7 +57,7 @@ SocketAdmin.reload = function (socket, data, callback) { }; SocketAdmin.restart = function (socket, data, callback) { - require('../../build').buildAll(function (err) { + require('../meta/build').buildAll(function (err) { if (err) { return callback(err); } diff --git a/test/mocks/databasemock.js b/test/mocks/databasemock.js index 67d896b255..82c40116fd 100644 --- a/test/mocks/databasemock.js +++ b/test/mocks/databasemock.js @@ -143,7 +143,7 @@ nconf.set('theme_config', path.join(nconf.get('themes_path'), 'nodebb-theme-persona', 'theme.json')); nconf.set('bcrypt_rounds', 1); - require('../../build').buildTargets(['js', 'clientCSS', 'acpCSS', 'tpl'], next); + next(); }, function (next) { var webserver = require('../../src/webserver');