Merge pull request #45 from wistityhq/feature/settings

Add settings tools for the Studio
This commit is contained in:
Loïc Saint-Roch 2015-12-02 17:13:02 +01:00
commit f9fd950c4f
7 changed files with 196 additions and 97 deletions

View File

@ -59,8 +59,19 @@ module.exports = function (strapi) {
}, cb);
},
// Load environment-specific config from `./config/environments/**/*.js|json`.
// Load all environments config from `./config/environments/*/*.js|json`.
// Not really used inside the framework but useful for the Studio.
'config/environments/**': function (cb) {
dictionary.optional({
dirname: path.resolve(strapi.config.appPath, strapi.config.paths.config, 'environments'),
filter: /(.+)\.(js|json)$/,
identity: false,
depth: 4
}, cb);
},
// Load environment-specific config from `./config/environments/**/*.js|json`.
'config/environments/*': function (cb) {
dictionary.aggregate({
dirname: path.resolve(strapi.config.appPath, strapi.config.paths.config, 'environments', strapi.config.environment),
filter: /(.+)\.(js|json)$/,
@ -90,10 +101,13 @@ module.exports = function (strapi) {
// Merge every user config together.
const mergedConfig = _.merge(
config['config/*'],
config['config/environments/**'],
config['config/environments/*'],
config['config/functions/*']
);
// Remove cache
delete require.cache[path.resolve(strapi.config.appPath, 'package.json')];
// Local `package.json`.
const packageJSON = require(path.resolve(strapi.config.appPath, 'package.json'));
@ -121,8 +135,8 @@ module.exports = function (strapi) {
strapi.config.orm = ormConfig.orm;
}
// Save different environments inside an array because we need it in the Strapi Studio.
strapi.config.environments = fs.readdirSync(path.resolve(strapi.config.appPath, strapi.config.paths.config, 'environments'));
// Save different environments because we need it in the Strapi Studio.
strapi.config.environments = config['config/environments/**'] || {};
// Make the application name in config match the server one.
strapi.app.name = strapi.config.name;

View File

@ -23,7 +23,7 @@ module.exports = function (strapi) {
defaults: {
i18n: {
defaultLocale: 'en',
defaultLocale: 'en_US',
modes: ['query', 'subdomain', 'cookie', 'header', 'url', 'tld'],
cookieName: 'locale'
}

View File

@ -98,7 +98,7 @@ module.exports = function (strapi) {
def.config = def.config || {};
// List of environments to run in, if empty defaults to all.
def.config.environments = def.config.environments || [];
def.config.environments = def.config.environments || {};
return def;
}

View File

@ -151,63 +151,74 @@ module.exports = function (strapi) {
return deferred.promise;
};
syncPromise(_.first(data.files), 0)
.then(function () {
if (data.hasOwnProperty('action') && _.isFunction(_self[data.action])) {
_self[data.action](data, function (err, obj) {
if (_.isEmpty(data.files)) {
fn({
appId: strapi.config.studio.appId,
token: strapi.token,
encrypted: strapi.rsa.encrypt({
err: null,
data: stringify({}, null, 2)
})
});
} else {
syncPromise(_.first(data.files), 0)
.then(function () {
if (data.hasOwnProperty('action') && _.isFunction(_self[data.action])) {
_self[data.action](data, function (err, obj) {
if (err) {
fn({
appId: strapi.config.studio.appId,
token: strapi.token,
encrypted: strapi.rsa.encrypt({
err: stringify(err, null, 2),
data: null
})
});
return false;
}
if (err) {
fn({
appId: strapi.config.studio.appId,
token: strapi.token,
encrypted: strapi.rsa.encrypt({
err: stringify(err, null, 2),
data: null
err: null,
data: stringify(obj, null, 2)
})
});
return false;
}
});
} else if (!data.hasOwnProperty('action')) {
fn({
appId: strapi.config.studio.appId,
token: strapi.token,
encrypted: strapi.rsa.encrypt({
err: null,
data: stringify(obj, null, 2)
data: stringify(true, null, 2)
})
});
});
} else if (!data.hasOwnProperty('action')) {
} else {
fn({
appId: strapi.config.studio.appId,
token: strapi.token,
encrypted: strapi.rsa.encrypt({
err: stringify('Unknow action', null, 2),
data: null
})
});
}
})
.catch(function (err) {
fn({
appId: strapi.config.studio.appId,
token: strapi.token,
encrypted: strapi.rsa.encrypt({
err: null,
data: stringify(true, null, 2)
})
});
} else {
fn({
appId: strapi.config.studio.appId,
token: strapi.token,
encrypted: strapi.rsa.encrypt({
err: stringify('Unknow action', null, 2),
err: err,
data: null
})
});
}
})
.catch(function (err) {
fn({
appId: strapi.config.studio.appId,
token: strapi.token,
encrypted: strapi.rsa.encrypt({
err: err,
data: null
})
});
});
}
} else if (!data.hasOwnProperty('action')) {
fn(strapi.rsa.encrypt(stringify('`action` attribute is missing', null, 2)), strapi.rsa.encryptPrivate(null));
} else if (_.isFunction(_self[data.action])) {
@ -262,6 +273,9 @@ module.exports = function (strapi) {
connectWithStudio: function (socket) {
strapi.log.info('Connection with the Studio server found, please wait a few seconds...');
// Purge
delete strapi.rsa;
strapi.rsa = new RSA({
b: 2048
});
@ -296,21 +310,6 @@ module.exports = function (strapi) {
});
},
/**
* Subaction for config
*
* @param {Object} data
*
* @return {Function} cb
*/
handleConfig: function (data, cb) {
strapi.log.warn('We need to flush server.');
strapi.log.warn('Install dependencies if we have to.');
cb(null, true);
},
/**
* Pull global strapi variable from local server
*
@ -341,6 +340,35 @@ module.exports = function (strapi) {
cb(null, obj);
},
/**
* Pull file from local server
*
* @param {Object} data
*
* @return {Function} cb
*/
pullFile: function (data, cb) {
const rootPath = path.resolve(data.path);
fs.exists(rootPath, function (exists) {
if (exists) {
fs.readFile(rootPath, 'utf8', function (err, data) {
if (err) {
cb('Impossible to read `' + rootPath + '`', null);
} else {
cb(null, {
path: rootPath,
value: JSON.parse(data)
});
}
});
} else {
cb('Unknow path `' + rootPath + '`', null);
}
});
},
/**
* Rebuild dictionary
*

View File

@ -7,7 +7,7 @@
// Node.js core.
const cluster = require('cluster');
const path = require('path');
const spawn = require('child_process').spawnSync;
const spawn = require('child_process').spawn;
// Public node modules.
const _ = require('lodash');
@ -75,14 +75,8 @@ module.exports = function (strapi) {
try {
strapi.adapters[name] = require(path.resolve(strapi.config.appPath, 'node_modules', adapter));
} catch (err) {
if (strapi.config.environment === 'development') {
strapi.log.warn('Installing the `' + adapter + '` adapter, please wait...');
spawn('npm', ['install', adapter, '--save']);
} else {
strapi.log.error('The adapter `' + adapter + '` is not installed.');
strapi.log.error('Execute `$ npm install ' + adapter + ' --save` to install it.');
process.exit(1);
}
strapi.log.error('The adapter `' + adapter + '` is not installed.');
process.exit(1);
}
});
@ -255,6 +249,51 @@ module.exports = function (strapi) {
next();
}
}, cb);
},
/**
* Installation adapters
*/
installation: function () {
const done = _.after(_.size(strapi.config.orm.adapters), function () {
strapi.emit('hook:waterline:installed');
});
_.forEach(strapi.config.orm.adapters, function (adapter) {
try {
require(path.resolve(strapi.config.appPath, 'node_modules', adapter));
done();
} catch (err) {
if (strapi.config.environment === 'development') {
strapi.log.warn('Installing the `' + adapter + '` adapter, please wait...');
console.log();
const process = spawn('npm', ['install', adapter, '--save']);
process.on('error', function (error) {
strapi.log.error('The adapter `' + adapter + '` has not been installed.');
strapi.log.error(error);
process.exit(1);
});
process.on('close', function (code) {
if (code !== 0) {
strapi.log.error('The adapter `' + adapter + '` has not been installed.');
strapi.log.error('Code: ' + code);
process.exit(1);
}
done();
});
} else {
strapi.log.error('The adapter `' + adapter + '` is not installed.');
strapi.log.error('Execute `$ npm install ' + adapter + ' --save` to install it.');
process.exit(1);
}
}
});
}
};

View File

@ -138,6 +138,9 @@ module.exports = strapi => {
// zero downtime reloads.
if (_.isPlainObject(strapi.config.reload) && !_.isEmpty(strapi.config.reload) && strapi.config.reload.workers > 0) {
herd(strapi.config.name)
.close(function () {
process.send('message');
})
.timeout(strapi.config.reload.timeout)
.size(strapi.config.reload.workers)
.run(function () {

View File

@ -17,6 +17,7 @@ const async = require('async');
*/
module.exports = cb => {
const self = this;
console.log();
@ -30,12 +31,12 @@ module.exports = cb => {
// Rebuild the dictionaries.
dictionaries: cb => {
this.on('hook:_config:reloaded', () => {
this.on('hook:_api:reloaded', () => cb());
this.hooks._api.reload();
self.on('hook:_config:reloaded', () => {
self.on('hook:_api:reloaded', () => cb());
self.hooks._api.reload();
});
this.hooks._config.reload();
self.hooks._config.reload();
}
},
@ -44,45 +45,59 @@ module.exports = cb => {
// Just in case there is an error.
if (err) {
this.log.error('Impossible to reload the server');
this.log.error('Please restart the server manually');
this.stop();
self.log.error('Impossible to reload the server');
self.log.error('Please restart the server manually');
self.stop();
}
// Tell the application the framework is reloading
// (might be used by some hooks).
this.reloading = true;
self.reloading = true;
// Teardown Waterline adapters and
// reload the Waterline ORM.
this.after('hook:waterline:reloaded', () => {
this.after('hook:router:reloaded', () => {
process.nextTick(() => cb());
// Run adapters installation
if (cluster.isMaster) {
self.hooks.waterline.installation();
}
// Update `strapi` status.
this.reloaded = true;
this.reloading = false;
// Install new adapters
strapi.after('hook:waterline:installed', () => {
self.log.warn('Application is restarting...');
console.log();
// Finally inform the developer everything seems ok.
if (cluster.isMaster && _.isPlainObject(strapi.config.reload) && !_.isEmpty(strapi.config.reload) && strapi.config.reload.workers < 1) {
this.log.info('Application\'s dictionnary updated');
this.log.warn('You still need to restart your server to fully enjoy changes...');
}
// Teardown Waterline adapters and
// reload the Waterline ORM.
self.after('hook:waterline:reloaded', () => {
self.after('hook:router:reloaded', () => {
process.nextTick(() => cb());
// Kill every worker processes.
_.forEach(cluster.workers, () => process.kill(process.pid, 'SIGHUP'));
// Update `strapi` status.
self.reloaded = true;
self.reloading = false;
if (cluster.isMaster && _.isPlainObject(strapi.config.reload) && !_.isEmpty(strapi.config.reload) && strapi.config.reload.workers > 0) {
this.log.info('Application restarted');
console.log();
}
// Finally inform the developer everything seems ok.
if (cluster.isMaster && _.isPlainObject(strapi.config.reload) && !_.isEmpty(strapi.config.reload) && strapi.config.reload.workers < 1) {
self.log.info('Application\'s dictionnary updated');
self.log.warn('You still need to restart your server to fully enjoy changes...');
}
self.once('restart:done', function () {
strapi.log.info('Application successfully restarted');
});
if (cluster.isMaster) {
_.forEach(cluster.workers, worker => worker.on('message', () => self.emit('restart:done')));
}
// Kill every worker processes.
_.forEach(cluster.workers, () => process.kill(process.pid, 'SIGHUP'));
});
// Reloading the router.
self.hooks.router.reload();
});
// Reloading the router.
this.hooks.router.reload();
// Reloading the ORM.
self.hooks.waterline.reload();
});
// Reloading the ORM.
this.hooks.waterline.reload();
});
};