diff --git a/core/boot.js b/core/boot.js index 04112ca010..fd6b5136b4 100644 --- a/core/boot.js +++ b/core/boot.js @@ -208,7 +208,6 @@ async function bootGhost() { debug('End: Load sentry'); debug('Begin: load server + minimal app'); - process.env.NODE_ENV = process.env.NODE_ENV || 'development'; // Get minimal application in maintenance mode const rootApp = require('./app'); @@ -241,7 +240,7 @@ async function bootGhost() { mountGhost(rootApp, ghostApp); // Announce Server Readiness - logging.info('Ghost boot', (Date.now() - startTime) / 1000 + 's'); + logging.info('Ghost booted', (Date.now() - startTime) / 1000 + 's'); debug('boot announcing readiness'); GhostServer.announceServerReadiness(); diff --git a/core/frontend/services/themes/index.js b/core/frontend/services/themes/index.js index 8ef7c1f74c..d46fde75d7 100644 --- a/core/frontend/services/themes/index.js +++ b/core/frontend/services/themes/index.js @@ -23,11 +23,8 @@ module.exports = { debug('init themes', activeThemeName); - // Register a listener for server-start to load all themes - events.on('server.start', function readAllThemesOnServerStart() { - themeLoader.loadAllThemes(); - }); - events.on('themes.ready', function readAllThemesOnServerStart() { + // Register a listener for when the server says we can start to load all themes + events.on('themes.ready', function readAllThemesOnReady() { themeLoader.loadAllThemes(); }); diff --git a/core/index.js b/core/index.js deleted file mode 100644 index 9b2fe143c4..0000000000 --- a/core/index.js +++ /dev/null @@ -1,26 +0,0 @@ -// ## Server Loader -// Passes options through the boot process to get a server instance back -const server = require('./server'); -const errors = require('@tryghost/errors'); -const GhostServer = require('./server/ghost-server'); - -// Set the default environment to be `development` -process.env.NODE_ENV = process.env.NODE_ENV || 'development'; - -function makeGhost(options) { - options = options || {}; - - return server(options) - .catch((err) => { - if (!errors.utils.isIgnitionError(err)) { - err = new errors.GhostError({message: err.message, err: err}); - } - - return GhostServer.announceServerReadiness(err) - .finally(() => { - throw err; - }); - }); -} - -module.exports = makeGhost; diff --git a/core/server/data/db/migrator.js b/core/server/data/db/migrator.js deleted file mode 100644 index cd3584a4e4..0000000000 --- a/core/server/data/db/migrator.js +++ /dev/null @@ -1,74 +0,0 @@ -const KnexMigrator = require('knex-migrator'); -const config = require('../../../shared/config'); -const errors = require('@tryghost/errors'); - -const knexMigrator = new KnexMigrator({ - knexMigratorFilePath: config.get('paths:appRoot') -}); - -module.exports.getState = () => { - let state; - let err; - - return knexMigrator.isDatabaseOK() - .then(() => { - state = 1; - return state; - }) - .catch((_err) => { - err = _err; - - // CASE: database was never created - if (err.code === 'DB_NOT_INITIALISED') { - state = 2; - return state; - } - - // CASE: you have created the database on your own, you have an existing none compatible db? - if (err.code === 'MIGRATION_TABLE_IS_MISSING') { - state = 3; - return state; - } - - // CASE: database needs migrations - if (err.code === 'DB_NEEDS_MIGRATION') { - state = 4; - return state; - } - - // CASE: database connection errors, unknown cases - throw err; - }); -}; - -module.exports.dbInit = () => { - return knexMigrator.init(); -}; - -module.exports.migrate = () => { - return knexMigrator.migrate(); -}; - -module.exports.isDbCompatible = (connection) => { - return connection.raw('SELECT `key` FROM settings WHERE `key`="databaseVersion";') - .then((response) => { - if (!response || !response[0].length) { - return; - } - - throw new errors.DatabaseVersionError({ - message: 'Your database version is not compatible with Ghost 2.0.', - help: 'Want to keep your DB? Use Ghost < 1.0.0 or the "0.11" branch.' + - '\n\n\n' + - 'Want to migrate Ghost 0.11 to 2.0? Please visit https://ghost.org/docs/update/' - }); - }) - .catch((err) => { - // CASE settings table doesn't exists - if (err.errno === 1146 || err.errno === 1) { - return; - } - - throw err; - }); -}; diff --git a/core/server/ghost-server.js b/core/server/ghost-server.js index aeb400c4a9..8d360492d4 100644 --- a/core/server/ghost-server.js +++ b/core/server/ghost-server.js @@ -199,15 +199,6 @@ class GhostServer { } } - /** - * @param {Object} externalApp - express app instance - * @return {Promise} Resolves once Ghost has switched HTTP Servers - */ - async swapHttpApp(externalApp) { - await this._stopServer(); - await this.start(externalApp); - } - /** * ### Hammertime * To be called after `stop` diff --git a/core/server/index.js b/core/server/index.js deleted file mode 100644 index 3d0679eaef..0000000000 --- a/core/server/index.js +++ /dev/null @@ -1,203 +0,0 @@ -/** - * make sure overrides get's called first! - * - keeping the overrides import here works for installing Ghost as npm! - * - * the call order is the following: - * - root index requires core module - * - core index requires server - * - overrides is the first package to load - */ -require('./overrides'); - -const debug = require('ghost-ignition').debug('boot:init'); -const Promise = require('bluebird'); -const config = require('../shared/config'); -const {events, i18n} = require('./lib/common'); -const logging = require('../shared/logging'); -const migrator = require('./data/db/migrator'); -const urlUtils = require('./../shared/url-utils'); - -// Frontend Components -const themeService = require('../frontend/services/themes'); -const appService = require('../frontend/services/apps'); -const frontendSettings = require('../frontend/services/settings'); - -async function initialiseServices() { - // CASE: When Ghost is ready with bootstrapping (db migrations etc.), we can trigger the router creation. - // Reason is that the routers access the routes.yaml, which shouldn't and doesn't have to be validated to - // start Ghost in maintenance mode. - // Routing is a bridge between the frontend and API - const routing = require('../frontend/services/routing'); - // We pass the themeService API version here, so that the frontend services are less tightly-coupled - routing.bootstrap.start(themeService.getApiVersion()); - - const settings = require('./services/settings'); - const permissions = require('./services/permissions'); - const xmlrpc = require('./services/xmlrpc'); - const slack = require('./services/slack'); - const {mega} = require('./services/mega'); - const webhooks = require('./services/webhooks'); - const scheduling = require('./adapters/scheduling'); - - debug('`initialiseServices` Start...'); - const getRoutesHash = () => frontendSettings.getCurrentHash('routes'); - - await Promise.all([ - // Initialize the permissions actions and objects - permissions.init(), - xmlrpc.listen(), - slack.listen(), - mega.listen(), - webhooks.listen(), - settings.syncRoutesHash(getRoutesHash), - appService.init(), - scheduling.init({ - // NOTE: When changing API version need to consider how to migrate custom scheduling adapters - // that rely on URL to lookup persisted scheduled records (jobs, etc.). Ref: https://github.com/TryGhost/Ghost/pull/10726#issuecomment-489557162 - apiUrl: urlUtils.urlFor('api', {version: 'v3', versionType: 'admin'}, true) - }) - ]); - - debug('XMLRPC, Slack, MEGA, Webhooks, Scheduling, Permissions done'); - - // Initialise analytics events - if (config.get('segment:key')) { - require('./analytics-events').init(); - } - - debug('...`initialiseServices` End'); -} - -async function initializeRecurringJobs() { - // we don't want to kick off scheduled/recurring jobs that will interfere with tests - if (process.env.NODE_ENV.match(/^testing/)) { - return; - } - - if (config.get('backgroundJobs:emailAnalytics')) { - const emailAnalyticsJobs = require('./services/email-analytics/jobs'); - await emailAnalyticsJobs.scheduleRecurringJobs(); - } -} - -const initExpressApps = async () => { - await frontendSettings.init(); - debug('Frontend settings done'); - - await themeService.init(); - debug('Themes done'); - - const parentApp = require('./web/parent/app')(); - debug('Express Apps done'); - - return parentApp; -}; - -/** - * - initialise models - * - initialise i18n - * - start the ghost server - * - load all settings into settings cache (almost every component makes use of this cache) - * - enable maintenance mode if migrations are missing - * - load active theme - * - create our express apps (site, admin, api) - */ -const minimalRequiredSetupToStartGhost = async (dbState) => { - const settings = require('./services/settings'); - const jobService = require('./services/jobs'); - const models = require('./models'); - const GhostServer = require('./ghost-server'); - - // Initialize Ghost core internationalization - i18n.init(); - debug('Default i18n done for core'); - - models.init(); - debug('Models done'); - - const ghostServer = new GhostServer(); - - ghostServer.registerCleanupTask(async () => { - await jobService.shutdown(); - }); - - // CASE: all good or db was just initialised - if (dbState === 1 || dbState === 2) { - await settings.init(); - debug('Settings done'); - const parentApp = await initExpressApps(); - ghostServer.rootApp = parentApp; - - events.emit('db.ready'); - - await initialiseServices(); - } - - // CASE: migrations required, put blog into maintenance mode - if (dbState === 4) { - config.set('maintenance:enabled', true); - logging.info('Blog is in maintenance mode.'); - - ghostServer.rootApp = require('./web/maintenance'); - - try { - migrator.migrate() - .then(async () => { - await settings.init(); - debug('Settings done'); - - const parentApp = await initExpressApps(); - ghostServer.swapHttpApp(parentApp); - - events.emit('db.ready'); - - await initialiseServices(); - - config.set('maintenance:enabled', false); - logging.info('Blog is out of maintenance mode.'); - - await GhostServer.announceServerReadiness(); - }); - } catch (err) { - try { - await GhostServer.announceServerReadiness(err); - } finally { - logging.error(err); - setTimeout(() => { - process.exit(1); - }, 100); - } - } - } - - initializeRecurringJobs(); - - return ghostServer; -}; - -/** - * Connect to database. - * Check db state. - */ -const isDatabaseInitialisationRequired = async () => { - const db = require('./data/db/connection'); - - let dbState = await migrator.getState(); - - // CASE: db initialisation required, wait till finished - if (dbState === 2) { - await migrator.dbInit(); - } - - // CASE: is db incompatible? e.g. you can't connect a 0.11 database with Ghost 1.0 or 2.0 - if (dbState === 3) { - await migrator.isDbCompatible(db); - - dbState = 2; - await migrator.dbInit(); - } - - return minimalRequiredSetupToStartGhost(dbState); -}; - -module.exports = isDatabaseInitialisationRequired; diff --git a/core/server/web/maintenance/index.js b/core/server/web/maintenance/index.js deleted file mode 100644 index 5b377496cb..0000000000 --- a/core/server/web/maintenance/index.js +++ /dev/null @@ -1,6 +0,0 @@ -const MaintenanceApp = require('@tryghost/maintenance'); -const express = require('../../../shared/express'); - -module.exports = new MaintenanceApp({ - express -}).app; diff --git a/ghost.js b/ghost.js index d05f0b897a..d5f889a837 100644 --- a/ghost.js +++ b/ghost.js @@ -1,14 +1,19 @@ -const argv = process.argv; +/** + * Internal CLI Placeholder + * + * If we want to add alternative commands, flags, or modify environment vars, it should all go here. + * Important: This file should not contain any requires, unless we decide to add pretty-cli/commander type tools + * + **/ -const mode = argv[2] || 'new'; +// Don't allow NODE_ENV to be null +process.env.NODE_ENV = process.env.NODE_ENV || 'development'; + +const argv = process.argv; +const mode = argv[2]; // Switch between boot modes switch (mode) { -case 'old': -case '3': - // Old boot sequence - require('./startup'); - break; default: // New boot sequence require('./core/boot')(); diff --git a/package.json b/package.json index 40bc361863..96329370b2 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,6 @@ "@tryghost/kg-markdown-html-renderer": "4.0.0-rc.2", "@tryghost/kg-mobiledoc-html-renderer": "4.0.0-rc.1", "@tryghost/magic-link": "0.6.6", - "@tryghost/maintenance": "0.1.0", "@tryghost/members-api": "1.0.0-rc.3", "@tryghost/members-csv": "0.4.4", "@tryghost/members-ssr": "0.8.10", diff --git a/startup.js b/startup.js deleted file mode 100644 index 1cde9e5f1a..0000000000 --- a/startup.js +++ /dev/null @@ -1,44 +0,0 @@ -// # Ghost Startup -// Orchestrates the startup of Ghost when run from command line. - -const startTime = Date.now(); -const debug = require('ghost-ignition').debug('boot:index'); -// Sentry must be initialised early on -const sentry = require('./core/shared/sentry'); - -debug('First requires...'); - -const ghost = require('./core'); - -debug('Required ghost'); - -const express = require('./core/shared/express'); -const logging = require('./core/shared/logging'); -const urlService = require('./core/frontend/services/url'); - -logging.info('Boot Mode: 3.0'); -// This is what listen gets called on, it needs to be a full Express App -const ghostApp = express('ghost'); - -// Use the request handler at the top level -// @TODO: decide if this should be here or in parent App - should it come after request id mw? -ghostApp.use(sentry.requestHandler); - -debug('Initialising Ghost'); - -ghost().then(function (ghostServer) { - // Mount our Ghost instance on our desired subdirectory path if it exists. - ghostApp.use(urlService.utils.getSubdir(), ghostServer.rootApp); - - debug('Starting Ghost'); - // Let Ghost handle starting our server instance. - return ghostServer.start(ghostApp) - .then(function afterStart() { - logging.info('Ghost boot', (Date.now() - startTime) / 1000 + 's'); - }); -}).catch(function (err) { - logging.error(err); - setTimeout(() => { - process.exit(-1); - }, 100); -}); diff --git a/test/utils/index.js b/test/utils/index.js index eefd1abf95..e7d3b3e609 100644 --- a/test/utils/index.js +++ b/test/utils/index.js @@ -14,13 +14,10 @@ const knexMigrator = new KnexMigrator(); // Ghost Internals const config = require('../../core/shared/config'); const boot = require('../../core/boot'); -const express = require('../../core/shared/express'); -const ghost = require('../../core/server'); const GhostServer = require('../../core/server/ghost-server'); const {events} = require('../../core/server/lib/common'); const db = require('../../core/server/data/db'); const models = require('../../core/server/models'); -const urlUtils = require('../../core/shared/url-utils'); const urlService = require('../../core/frontend/services/url'); const settingsService = require('../../core/server/services/settings'); const frontendSettingsService = require('../../core/frontend/services/settings'); @@ -216,21 +213,6 @@ const restartModeGhostStart = async () => { events.emit('server.start'); }; -// Old Boot Method -// const bootGhost = async (options) => { -// // Require Ghost -// ghostServer = await ghost(); - -// // Mount Ghost & Start Server -// if (options.subdir) { -// let parentApp = express('test parent'); -// parentApp.use(urlUtils.getSubdir(), ghostServer.rootApp); -// await ghostServer.start(parentApp); -// } else { -// await ghostServer.start(); -// } -// }; - const bootGhost = async () => { ghostServer = await boot(); }; diff --git a/yarn.lock b/yarn.lock index 49be0fc969..2b246cb245 100644 --- a/yarn.lock +++ b/yarn.lock @@ -557,13 +557,6 @@ jsonwebtoken "^8.5.1" lodash "^4.17.15" -"@tryghost/maintenance@0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@tryghost/maintenance/-/maintenance-0.1.0.tgz#cb2c4dff2c1292ca7a07b88f3a658832e33b3259" - integrity sha512-f91Wngx4UbzGuSlCN6TI9EAvS1nofIYY653+3OO3fx/2A9ehbzMRWraUH3GY05xKRc8CnW+msGkRrPgiMIa/Kw== - dependencies: - ghost-ignition "^4.4.3" - "@tryghost/members-api@1.0.0-rc.3": version "1.0.0-rc.3" resolved "https://registry.yarnpkg.com/@tryghost/members-api/-/members-api-1.0.0-rc.3.tgz#24dd56700f3da322a6a299a97b8632a1cae7db65" @@ -4141,7 +4134,7 @@ ghost-ignition@4.2.4: prettyjson "1.2.1" uuid "8.3.1" -ghost-ignition@4.4.3, ghost-ignition@^4.4.3: +ghost-ignition@4.4.3: version "4.4.3" resolved "https://registry.yarnpkg.com/ghost-ignition/-/ghost-ignition-4.4.3.tgz#c837ab11e1f3a1cfd22cc24df6b506a9afc1bc25" integrity sha512-eViE/ae+AGV/YmVbTq2W5TBWVu724EUJ0pjtSwa4q6o1+fXxMIqoELJaxMX+Gc9PBK0nI3J+E0JI8GdrEiqndg==