UNPKG

landmark-serve

Version:

Web Application Framework and Admin GUI / Content Management System built on Express.js and Mongoose

167 lines (157 loc) 5.18 kB
var _ = require('underscore'), fs = require('fs'), path = require('path'), async = require('async'), semver = require('semver'), landmark = require('../'), mongoose = landmark.mongoose, utils = require('landmark-utils'); var _dashes_ = '------------------------------------------------'; // Update Schema - automatically created and managed by Landmark when updates are used var UpdateModel = new mongoose.Schema({ key: { type: String, index: true }, appliedOn: { type: Date, default: Date.now } }, { collection: landmark.prefixModel('App_Update') }); mongoose.model('App_Update', UpdateModel); // Apply method - loads the available updates and applies any that haven't been, in order exports.apply = function(callback) { var Update = mongoose.model('App_Update'), updateCount = 0, deferCount = 0, skipCount = 0; var updatesPath = landmark.getPath('updates', 'updates'); var applyUpdate = function(file, done) { Update.findOne({ key: file }, function(err, updateRecord) { if (err) { console.error('Error searching database for update ' + file + ':'); console.dir(err); done(err); } else if (!updateRecord) { var update = require(path.join(updatesPath, file)); // skip updates that export a falsy value if (!update) { skipCount++; return done(); } // auto-wrap create scripts for a friendlier shorthand syntax if (_.isObject(update.create)) { var items = update.create, ops = update.options || {}; update = function(done) { landmark.createItems(items, ops, function(err, stats) { stats && console.log(stats.message); done(err); }); }; } // ensure type if (!_.isFunction(update)) { console.log('\nError in update file ./updates/' + file + '.js\nUpdate files must export a function\n'); process.exit(); } // if an update is deferred, don't process it if (update.__defer__) { deferCount++; return done(); } // if there are deferred updates, don't process any subsequent ones if (deferCount) { skipCount++; return done(); } console.log(_dashes_ + '\nApplying update ' + file + '...'); if (update.__background__) { updateCount++; update(function(err) { if (err) { console.log(_dashes_ + '\nUpdate ' + file + ' (background mode) failed with error:'); console.log(err); } else { console.log(_dashes_ + '\nSuccessfully applied update ' + file + ' (in background).'); if (update.__commit__ !== false) { new Update({key: file}).save(); } } }); done(); } else { update(function(err) { if (err) { console.log(_dashes_ + '\nUpdate ' + file + ' failed with error:'); console.log(err); done(err); } else { updateCount++; console.log(_dashes_ + '\nSuccessfully applied update ' + file + '.'); if (update.__commit__ === false) { done(); } else { new Update({key: file}).save(done); } } }); } } else { done(); } }); }; if (!fs.existsSync(updatesPath)) { console.log('\nLandmarkJS Update Error:\n\n' + 'An updates folder must exist in your project root to use automatic updates.\n' + 'If you want to use a custom path for your updates, set the `updates` option.\n' + 'If you don\'t want to use updates, set the `auto update` option to `false`.\n' + 'See http://getlandmarkproject.com/docs/cms/configuration/#updates for more information.\n'); process.exit(); } var updates = fs.readdirSync(updatesPath) .map(function(i) { // exclude non-javascript or coffee files in the updates folder return (path.extname(i) != '.js' && path.extname(i) != '.coffee') ? false : path.basename(i, '.js'); }).filter(function(i) { // exclude falsy values and filenames that without a valid semver return i && semver.valid(i.split('-')[0]); }).sort(function(a, b) { // exclude anything after a hyphen from the version number return semver.compare(a.split('-')[0], b.split('-')[0]); }); async.eachSeries(updates, applyUpdate, function(err) { if (updateCount || deferCount || skipCount) { var status = ''; if (updateCount) { status += 'Successfully applied ' + utils.plural(updateCount, '* update'); if (skipCount || deferCount) { status += ', '; } } if (deferCount) { status += 'Deferred ' + utils.plural(deferCount, '* update'); if (skipCount) { status += ', '; } } if (skipCount) { status += 'Skipped ' + utils.plural(skipCount, '* update'); } status += '.'; console.log(_dashes_ + '\n' + status + '\n' + _dashes_); } if (err) { var errmsg = 'An error occurred applying updates, bailing on Landmark init.\n\nError details:'; if (!(updateCount || deferCount || skipCount)) { errmsg = _dashes_ + '\n' + errmsg; } console.error(errmsg); console.error(err); if ('stack' in err) { console.trace(err.stack); } // wait till nextTick to exit so the trace completes. process.nextTick(function() { process.exit(1); }); return; } callback && callback(); }); };