From 32ac3a9facf0d08a244686dd2c38d71c8cb3ea3a Mon Sep 17 00:00:00 2001 From: NGPixel Date: Tue, 18 Apr 2017 20:23:42 -0400 Subject: [PATCH] Added support for Heroku + config wizard fixes --- configure.js | 3 +- fuse.js | 3 +- init.js | 101 ++++++++++++++++++++++++++++++++++++ npm/install.js | 16 +++--- package.json | 4 +- views/configure/index.pug | 4 +- wiki.js | 104 ++++++++++++++------------------------ 7 files changed, 155 insertions(+), 80 deletions(-) create mode 100644 init.js diff --git a/configure.js b/configure.js index 63a1d75c..d5b04bbd 100644 --- a/configure.js +++ b/configure.js @@ -125,7 +125,8 @@ module.exports = (port, spinner) => { */ app.post('/dbcheck', (req, res) => { let mongo = require('mongodb').MongoClient - mongo.connect(req.body.db, { + let mongoURI = (_.startsWith(req.body.db, '$')) ? process.env[req.body.db.slice(1)] : req.body.db + mongo.connect(mongoURI, { autoReconnect: false, reconnectTries: 2, reconnectInterval: 1000, diff --git a/fuse.js b/fuse.js index 798e2098..9128436d 100644 --- a/fuse.js +++ b/fuse.js @@ -82,7 +82,6 @@ const SHIMS = { console.info(colors.white('└── ') + colors.green('Running global tasks...')) -let preInitContent = '' let globalTasks = Promise.mapSeries([ /** * ACE Modes @@ -161,6 +160,7 @@ let globalTasks = Promise.mapSeries([ */ () => { console.info(colors.white(' └── ') + colors.green('Bundling pre-init scripts...')) + let preInitContent = '' return fs.readdirAsync('./client/js/pre-init').map(f => { let fPath = path.join('./client/js/pre-init/', f) return fs.readFileAsync(fPath, 'utf8').then(fContent => { @@ -275,7 +275,6 @@ globalTasks.then(() => { shim: SHIMS, plugins: [ fsbx.EnvPlugin({ NODE_ENV: 'production' }), - fsbx.BannerPlugin(preInitContent), [ fsbx.SassPlugin({ outputStyle: 'compressed', includePaths: ['./node_modules/requarks-core'] }), fsbx.CSSPlugin() ], fsbx.BabelPlugin({ config: { diff --git a/init.js b/init.js new file mode 100644 index 00000000..fddd8c40 --- /dev/null +++ b/init.js @@ -0,0 +1,101 @@ +'use strict' + +const Promise = require('bluebird') +const fs = Promise.promisifyAll(require('fs-extra')) +const pm2 = Promise.promisifyAll(require('pm2')) +const ora = require('ora') +const path = require('path') + +module.exports = { + /** + * Detect the most appropriate start mode + */ + startDetect: function () { + if (!process.env.IS_HEROKU) { + return this.startInHerokuMode() + } else { + return this.startInBackgroundMode() + } + }, + /** + * Start in background mode + */ + startInBackgroundMode: function () { + let spinner = ora('Initializing...').start() + return fs.emptyDirAsync(path.join(__dirname, './logs')).then(() => { + return pm2.connectAsync().then(() => { + return pm2.startAsync({ + name: 'wiki', + script: 'server.js', + cwd: __dirname, + output: path.join(__dirname, './logs/wiki-output.log'), + error: path.join(__dirname, './logs/wiki-error.log'), + minUptime: 5000, + maxRestarts: 5 + }).then(() => { + spinner.succeed('Wiki.js has started successfully.') + }).finally(() => { + pm2.disconnect() + }) + }) + }).catch(err => { + spinner.fail(err) + process.exit(1) + }) + }, + /** + * Start in Heroku mode + */ + startInHerokuMode: function () { + let self = this + + console.info('Initializing Wiki.js for Heroku...') + let herokuStatePath = path.join(__dirname, './app/heroku.json') + return fs.accessAsync(herokuStatePath).then(() => { + require('./server.js') + }).catch(err => { + if (err.code === 'ENOENT') { + console.info('Wiki.js is not configured yet. Launching configuration wizard...') + self.configure(process.env.PORT) + } else { + console.error(err) + process.exit(1) + } + }) + }, + /** + * Stop Wiki.js process(es) + */ + stop () { + let spinner = ora('Shutting down Wiki.js...').start() + return pm2.connectAsync().then(() => { + return pm2.stopAsync('wiki').then(() => { + spinner.succeed('Wiki.js has stopped successfully.') + }).finally(() => { + pm2.disconnect() + }) + }).catch(err => { + spinner.fail(err) + process.exit(1) + }) + }, + /** + * Restart Wiki.js process(es) + */ + restart: function () { + let self = this + return self.stop().delay(1000).then(() => { + self.startDetect() + }) + }, + /** + * Start the web-based configuration wizard + * + * @param {Number} port Port to bind the HTTP server on + */ + configure (port) { + port = port || 3000 + let spinner = ora('Initializing interactive setup...').start() + require('./configure')(port, spinner) + } +} diff --git a/npm/install.js b/npm/install.js index 42731fd8..22b4f2b5 100644 --- a/npm/install.js +++ b/npm/install.js @@ -205,13 +205,15 @@ const tasks = { // INSTALL SEQUENCE // ===================================================== -console.info(colors.yellow( - ' __ __ _ _ _ _ \n' + - '/ / /\\ \\ (_) | _(_) (_)___ \n' + - '\\ \\/ \\/ / | |/ / | | / __| \n' + - ' \\ /\\ /| | <| |_ | \\__ \\ \n' + - ' \\/ \\/ |_|_|\\_\\_(_)/ |___/ \n' + - ' |__/\n')) +if (!process.env.IS_HEROKU) { + console.info(colors.yellow( + ' __ __ _ _ _ _ \n' + + '/ / /\\ \\ (_) | _(_) (_)___ \n' + + '\\ \\/ \\/ / | |/ / | | / __| \n' + + ' \\ /\\ /| | <| |_ | \\__ \\ \n' + + ' \\/ \\/ |_|_|\\_\\_(_)/ |___/ \n' + + ' |__/\n')) +} let ora = require('ora')({ text: 'Initializing...', spinner: 'dots12' }).start() diff --git a/package.json b/package.json index eda3656f..31c3dd2a 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,6 @@ "cheerio": "^0.22.0", "child-process-promise": "^2.2.1", "chokidar": "^1.6.1", - "commander": "^2.9.0", "compression": "^1.6.2", "connect-flash": "^0.1.1", "connect-mongo": "^1.3.2", @@ -120,7 +119,8 @@ "through2": "^2.0.3", "validator": "^7.0.0", "validator-as-promised": "^1.0.2", - "winston": "^2.3.1" + "winston": "^2.3.1", + "yargs": "^7.1.0" }, "devDependencies": { "babel-cli": "^6.24.1", diff --git a/views/configure/index.pug b/views/configure/index.pug index 13eb469a..40c4c095 100644 --- a/views/configure/index.pug +++ b/views/configure/index.pug @@ -160,8 +160,8 @@ html(data-logic='configure') section p.control.is-fullwidth label.label MongoDB Connection String - input(type='text', placeholder='e.g. mongodb://localhost:27017/wiki', v-model='conf.db', data-vv-scope='db', name='ipt-db', v-validate='{ required: true, min: 14 }') - span.desc The connection string to your MongoDB server. Leave the default localhost value if MongoDB is installed on the same server. + input(type='text', placeholder='e.g. mongodb://localhost:27017/wiki', v-model='conf.db', data-vv-scope='db', name='ipt-db', v-validate='{ required: true, min: 3 }') + span.desc The connection string to your MongoDB server. Leave the default localhost value if MongoDB is installed on the same server.
You can also specify an environment variable as the connection string (e.g. $MONGO_URI). .panel-footer .progress-bar: div(v-bind:style='{width: currentProgress}') button.button.is-indigo.is-outlined(v-on:click='proceedToConsiderations', v-bind:disabled='loading') Back diff --git a/wiki.js b/wiki.js index b128d48f..113e941a 100644 --- a/wiki.js +++ b/wiki.js @@ -7,74 +7,46 @@ // Licensed under AGPLv3 // =========================================== -const Promise = require('bluebird') -const fs = Promise.promisifyAll(require('fs-extra')) -const ora = require('ora') -const pm2 = Promise.promisifyAll(require('pm2')) -const cmdr = require('commander') -const path = require('path') +const init = require('./init') -const packageObj = fs.readJsonSync('package.json') - -cmdr.version(packageObj.version) - -cmdr.command('start') - .description('Start Wiki.js process') - .action(() => { - if (process.env.HEROKU) { - console.info('Initializing Wiki.js for Heroku...') - // todo - } else { - let spinner = ora('Initializing...').start() - fs.emptyDirAsync(path.join(__dirname, './logs')).then(() => { - return pm2.connectAsync().then(() => { - return pm2.startAsync({ - name: 'wiki', - script: 'server.js', - cwd: __dirname, - output: path.join(__dirname, './logs/wiki-output.log'), - error: path.join(__dirname, './logs/wiki-error.log'), - minUptime: 5000, - maxRestarts: 5 - }).then(() => { - spinner.succeed('Wiki.js has started successfully.') - }).finally(() => { - pm2.disconnect() - }) - }) - }).catch(err => { - spinner.fail(err) - process.exit(1) - }) +require('yargs') // eslint-disable-line no-unused-expressions + .usage('Usage: node $0 [args]') + .command({ + command: 'start', + alias: ['boot', 'init'], + desc: 'Start Wiki.js process', + handler: argv => { + init.startDetect() } }) - -cmdr.command('stop') - .description('Stop Wiki.js process') - .action(() => { - let spinner = ora('Shutting down Wiki.js...').start() - pm2.connectAsync().then(() => { - return pm2.stopAsync('wiki').then(() => { - spinner.succeed('Wiki.js has stopped successfully.') - }).finally(() => { - pm2.disconnect() - }) - }).catch(err => { - spinner.fail(err) - process.exit(1) - }) + .command({ + command: 'stop', + alias: ['quit', 'exit'], + desc: 'Stop Wiki.js process', + handler: argv => { + init.stop() + } }) - -cmdr.command('configure [port]') - .description('Configure Wiki.js') - .action((port) => { - port = port || 3000 - let spinner = ora('Initializing interactive setup...').start() - require('./configure')(port, spinner) + .command({ + command: 'restart', + alias: ['reload'], + desc: 'Restart Wiki.js process', + handler: argv => { + init.restart() + } }) - -cmdr.parse(process.argv) - -if (!process.argv.slice(2).length) { - cmdr.help() -} + .command({ + command: 'configure [port]', + alias: ['config', 'conf', 'cfg', 'setup'], + desc: 'Configure Wiki.js using the web-based setup wizard', + builder: (yargs) => yargs.default('port', 3000), + handler: argv => { + init.configure(argv.port) + } + }) + .recommendCommands() + .demandCommand(1, 'You must provide one of the accepted commands above.') + .help() + .version() + .epilogue('Read the docs at https://wiki.requarks.io') + .argv