Permalink
Browse files

Merge pull request #905 from caridy/multi-appjson

fixes [gh238] [bz5667423] support for multiple application configuration files
  • Loading branch information...
2 parents 69270fa + 2a796b6 commit eb4947ea870a2258176b7a9f0eef305b86786d81 @caridy caridy committed Jan 11, 2013
View
@@ -4,6 +4,7 @@
*.bak
*~
node_modules
+!tests/fixtures/app-jsons/node_modules
!tests/fixtures/packages/node_modules
!tests/fixtures/packages/node_modules/*/node_modules
arrowreport
@@ -50,6 +50,7 @@ YUI.add('addon-rs-config', function(Y, NAME) {
this._jsonCache = {}; // fullPath: contents as JSON object
this._ycbCache = {}; // fullPath: context: YCB config object
this._ycbDims = this._readYcbDimensions();
+ this._ycbAppConfig = this._readYcbAppConfig();
},
@@ -64,6 +65,16 @@ YUI.add('addon-rs-config', function(Y, NAME) {
/**
+ * Returns the YCB library object for the application config.
+ * @method getAppConfigYCB
+ * @return {YCB} YCB library object for the application config
+ */
+ getAppConfigYCB: function() {
+ return this._ycbAppConfig;
+ },
+
+
+ /**
* Same as readConfigSync except the result is cached for future calls.
* @method readConfigSimple
* @param {string} fullPath path to JSON or YAML file
@@ -165,6 +176,48 @@ YUI.add('addon-rs-config', function(Y, NAME) {
/**
+ * Creates a YCB configuration bundle using contents from multiple files.
+ * The appropriate dimensions.json file will be mixed in, and doesn't need
+ * to be part of the list of files.
+ * @method createMultipartYCB
+ * @param {array} paths list of files to load
+ * @return {YCB|undefined} return a YCB library object, or undefined if an error occurs
+ */
+ createMultipartYCB: function(paths) {
+ var p,
+ path,
+ config,
+ s,
+ section,
+ settings = {},
+ bundle = [];
+ bundle.push(this.getDimensions()[0]);
+ for (p = 0; p < paths.length; p += 1) {
+ path = paths[p];
+ config = this.readConfigSync(path);
+ if (!Y.Lang.isArray(config)) {
+ Y.log('not a YCB file: ' + path, 'error', NAME);
+ return;
+ }
+ for (s = 0; s < config.length; s += 1) {
+ section = config[s];
+ if (!Y.Lang.isArray(section.settings)) {
+ Y.log('missing "settings" in YCB file: ' + path, 'error', NAME);
+ return;
+ }
+ if (settings[section.settings]) {
+ Y.log('settings "' + section.settings + '" exists in both \n' + path + ' and\n' + settings[section.settings], 'error', NAME);
+ return;
+ }
+ settings[section.settings] = path;
+ bundle.push(section);
+ }
+ }
+ return new libycb.Ycb(bundle);
+ },
+
+
+ /**
* Using AOP, this is called after the ResourceStore's version.
* @method findResourceVersionByConvention
* @param {object} source metadata about where the resource is located
@@ -259,8 +312,46 @@ YUI.add('addon-rs-config', function(Y, NAME) {
path = libpath.join(this.mojitoRoot, 'dimensions.json');
}
return this.readConfigSimple(path);
- }
+ },
+
+ /**
+ * Initializes the special multi-file YCB library for all the application
+ * files. By default, we try to load `application.json`, then mix any other
+ * relative config file specified in the master section under the
+ * `applicationConfigFiles` array, which is optional.
+ * @private
+ * @method _readYcbAppConfig
+ * @return {object} libycb object
+ */
+ _readYcbAppConfig: function() {
+ var ycb,
+ i,
+ rootAppJSON = libpath.join(this.appRoot, 'application.json'),
+ paths = [],
+ relativePaths;
+
+ // trying to collect the app-level application.json which happens
+ // to be optional.
+ if (Y.Lang.isArray(this.readConfigSimple(rootAppJSON))) {
+ ycb = this.readConfigYCB(rootAppJSON, {});
+ // adding the master application.json as the top level
+ paths = [rootAppJSON];
+ // optional applicationConfigFiles to mix in more configs
+ relativePaths = ycb.applicationConfigFiles || [];
+ for (i = 0; i < relativePaths.length; i += 1) {
+ paths.push(libpath.join(this.appRoot, relativePaths[i]));
+ }
+ }
+
+ // Note: it doesn't matter if we try to reach the same file multiple
+ // times (application.json) because readConfigSync will cache it anyway
+ ycb = this.createMultipartYCB(paths);
+ if (!ycb) {
+ throw new Error("failed to create a YCB config from the following files:\n " + paths.join("\n "));
+ }
+ return ycb;
+ }
});
Y.namespace('mojito.addons.rs');
@@ -4,7 +4,7 @@
* See the accompanying LICENSE file for terms.
*/
-/*jslint anon:true, sloppy:true, nomen:true, stupid:true*/
+/*jslint anon:true, sloppy:true, nomen:true*/
/*global YUI*/
@@ -18,9 +18,6 @@
*/
YUI.add('addon-rs-selector', function(Y, NAME) {
- var libpath = require('path'),
- libycb = require('ycb');
-
function RSAddonSelector() {
RSAddonSelector.superclass.constructor.apply(this, arguments);
}
@@ -36,16 +33,10 @@ YUI.add('addon-rs-selector', function(Y, NAME) {
* @return {nothing}
*/
initializer: function(config) {
- var dims,
- json;
this.appRoot = config.appRoot;
this.mojitoRoot = config.mojitoRoot;
- dims = config.host.config.getDimensions();
- json = config.host.config.readConfigSimple(libpath.join(this.appRoot, 'application.json'));
- json = dims.concat(json);
- // TODO: use rs.config for this too
- this._appConfigYCB = new libycb.Ycb(json);
+ this._appConfigYCB = config.host.config.getAppConfigYCB();
this._poslCache = {}; // context: POSL
},
@@ -223,6 +223,8 @@ YUI.add('mojito-resource-store', function(Y, NAME) {
this._validDims = this._parseValidDims(this.config.getDimensions());
this.validateContext(this._config.context);
this._fwConfig = this.config.readConfigSimple(this._libs.path.join(this._config.mojitoRoot, 'config.json'));
+
+ this._appConfigYCB = this.config.getAppConfigYCB();
this._appConfigStatic = this.getAppConfig({});
},
destructor: function() {},
@@ -349,13 +351,14 @@ YUI.add('mojito-resource-store', function(Y, NAME) {
key,
ycb;
+ ctx = this.blendStaticContext(ctx);
key = JSON.stringify(ctx || {});
if (this._appConfigCache[key]) {
return JSON.parse(this._appConfigCache[key]);
}
- ycb = this.config.readConfigYCB(this._libs.path.join(this._config.root, 'application.json'), ctx);
+ ycb = this._appConfigYCB.read(ctx);
appConfig = Y.mojito.util.blend(this._fwConfig.appConfigBase, this._config.appConfig);
appConfig = Y.mojito.util.blend(appConfig, ycb);
@@ -364,6 +367,8 @@ YUI.add('mojito-resource-store', function(Y, NAME) {
return appConfig;
},
+
+
/**
* Preloads everything in the app, and as well pertinent parts of
* the framework.
@@ -374,10 +379,16 @@ YUI.add('mojito-resource-store', function(Y, NAME) {
preload: function() {
// We need to do an initial sweep to find the resource store addons.
this.preloadResourceVersions();
+
+ // We need to rebuild _appConfigStatic -before- we load the addons,
+ // since they might (they do) cache the results of getStaticAppConfig().
+ this._appConfigStatic = this.getAppConfig({});
+
// And then use them.
this.loadAddons();
// Then, do another sweep so that the loaded addons can be used.
this.preloadResourceVersions();
+
this.makeResourceVersions();
this.resolveResourceVersions();
},
@@ -0,0 +1,7 @@
+[
+ {
+ "testKey1": "testVal1",
+ "testKey2": "testVal2",
+ "testKey3": "testVal3"
+ }
+]
@@ -0,0 +1,8 @@
+{
+ "foo": {
+ "settings": [ "master" ],
+ "testKey1": "testVal1",
+ "testKey2": "testVal2",
+ "testKey3": "testVal3"
+ }
+}
@@ -0,0 +1,12 @@
+[
+ {
+ "settings": [ "master" ],
+ "applicationConfigFiles": [
+ "node_modules/devices/application.json",
+ "node_modules/runtimes/application.json"
+ ],
+ "testKey1": "testVal1",
+ "testKey2": "testVal2",
+ "testKey3": "testVal3"
+ }
+]
@@ -0,0 +1,8 @@
+[
+ {
+ "settings": [ "master" ],
+ "testKey1": "testVal1-app2",
+ "testKey2": "testVal2-app2",
+ "testKey3": "testVal3-app2"
+ }
+]

Some generated files are not rendered by default. Learn more.

Oops, something went wrong.

Some generated files are not rendered by default. Learn more.

Oops, something went wrong.
@@ -0,0 +1,13 @@
+{
+ "name": "root",
+ "version": "666.0.0",
+ "description": "root package",
+ "author": "Team Mojito (http://developer.yahoo.com/cocktails/mojito)",
+ "dependencies": {},
+ "main": ".",
+ "engines": {
+ "node": ">= 0.4.0",
+ "npm": ">= 1.0.0"
+ },
+ "devDependencies": {}
+}
Oops, something went wrong.

0 comments on commit eb4947e

Please sign in to comment.