polygulp
Version:
Indirect Gulpfile for Polymer projects
399 lines (324 loc) • 13.3 kB
JavaScript
/* global module, require */
/***********************************************************************************
Create custom config *
Features: *
- Create/Modify app.common.config: *
- app.common.config.appName *
- app.common.config.version *
- app.common.config.backend *
- app.common.config.webfs *
- app.common.config.analyticsID *
- app.common.config.compatibility *
- app.common.config.smartBanner *
- Extend default config.json with env config.json *
*
Project configuration: *
- Define a default config.json file in resources/config/config.json *
- Define environment config.json files in: resources/config/{{envName}}/config.json *
- Set debug flag in config.json to receive feedback of the task *
***********************************************************************************/
module.exports = function(gulp, config) {
'use strict';
var gutil = require('gulp-util');
var requireDir = require('require-dir');
var path = require('path');
var _ = require('underscore');
var fs = require('fs');
var mkdirp = require('mkdirp');
var argv = require('yargs').argv;
var playScraper = require('google-play-scraper');
var Download = require('download');
var base64 = require('base64-js');
var worldCountries = require('world-countries');
var projectConfig = requireDir(path.resolve(config.paths.app + '/resources/config'));
var projectConfigDir = path.resolve(config.paths.tmp + '/resources/config');
var distFolder = path.resolve(config.paths.dist);
var buildEnv;
if (argv.environment) {
buildEnv = argv.environment;
} else if (process && process.env) {
buildEnv = process.env.environment || process.env.NODE_ENV;
}
/**
* Check if exits url options (urlBase, domain and/or version)
* provided by command line or env variable and return them
* @method function
* @return {Object} url options
*/
var _customUrl = function() {
if (!argv.endpoint &&
(!process.env || !process.env.endpoint)) {
return {};
}
var endpointOptions = argv.endpoint || process.env.endpoint;
var backendCustomOptions = {};
var checkOptions = ['urlBase', 'domain', 'version'];
for (var i in checkOptions) {
if (endpointOptions[checkOptions[i]]) {
backendCustomOptions[checkOptions[i]] = endpointOptions[checkOptions[i]];
configLog.info('Using custom ' + checkOptions[i] + ': ' + endpointOptions[checkOptions[i]]);
}
}
return backendCustomOptions;
};
var initDirs = function() {
mkdirp.sync(projectConfigDir);
};
/**
* gutil wrappers to send custom feedback
* @type {Object}
*/
var configLog = {
debug: true,
_log: function(type, message) {
if (!this.debug) {
return;
}
gutil.log('config.json', gutil.colors[type](message));
},
success: function(message) {
this._log('green', message);
},
info: function(message) {
this._log('blue', message);
},
warning: function(message) {
this._log('yellow', message);
},
error: function(message) {
this._log('red', message);
}
};
/**
* Build a endpoints object with domain and/or version provided
* @method function
* @param {Object} endpoints
* @param {String} domain
* @param {String} version
* @return {Object}
* @example
* var endpoints = {"publishers": "publisher", "feedback": "feedback"};
* var domain = "demo";
* var version = "v0";
* buildEndpoints(endpoints, domain, version)
* ->
* {"publishers":"demo/snapshot/publisher/", "feedback":"demo/snapshot/feedback/"}
*/
var buildEndpoints = function(endpoints, domain, version) {
if (!endpoints) {
configLog.warning('No endpoints provided. Check endpoints config');
return '';
}
var builtEndpoints = {};
domain = domain ? (domain + '/') : '';
version = version ? (version + '/') : '';
for (var i in endpoints) {
builtEndpoints[i] = domain +
version +
endpoints[i] + '/';
}
return builtEndpoints;
};
/**
* Build backend config
* @method function
* @param {Object} options
* @return {String} Stringified js snippet with app.common.config.backend
*/
var buildBackendConfig = function(options) {
var backendConfig = _.clone(options.backend);
_.extend(backendConfig, _customUrl());
var endpoints = buildEndpoints(backendConfig.endpoints, backendConfig.domain, backendConfig.version);
backendConfig.endpoints = endpoints;
return addToConfig(options, 'backend', backendConfig);
};
/**
* Build smart banner config extracted from play store
* @method function
* @param {Object} options
* @return {Object} Promise resolved with a stringified snippet with app.common.config.smartBanner
*/
var buildSmartBannerConfig = function(options) {
var playScraperPromise = new Promise(function(resolve, reject) {
if (!options.smartBanner) {
var errorText = 'No smartBanner config provided';
configLog.warning(errorText);
reject(errorText);
return;
}
playScraper.app({
appId: options.smartBanner.id
}).then(function(res) {
var js;
var smartBannerConfig = {
extractedFromPlayStore: res,
title: res.title,
author: res.developer
};
if (res.icon) {
Download().get('https:' + res.icon)
.run(function(err, files) {
if (files && files[0]){
var imageConverted = base64.fromByteArray(files[0].contents);
smartBannerConfig.image = imageConverted;
}
if (err) {
configLog.warning('Error downloading smart banner icon: ' + err);
}
js = addToConfig(options, 'smartBanner', smartBannerConfig);
resolve(js);
});
return;
}
js = addToConfig(options, 'smartBanner', smartBannerConfig);
resolve(js);
}).catch(function(err) {
reject(err);
});
});
return playScraperPromise;
};
var orderCountries = function(countries) {
var orderedCountries = {};
var country;
for (var i in countries) {
country = countries[i];
orderedCountries[country.cca2] = country;
}
return orderedCountries;
};
/**
* Creates a new js snippet wich modify a param in app.common.config
* Optionally, if the param to modify is an object you can extend it
* @method function
* @param {Object} options
* @param {String} param
* @param {Object} extension
* @return {String} Stringified js snippet with app.common.config[param]
*/
var addToConfig = function(options, param, extension) {
if (!options[param]) {
configLog.warning('No ' + param + ' config provided');
return '';
}
var js = 'window.app.common.config["' + param + '"] = ';
var paramConfig = options[param];
if (extension) {
if (_.isObject(paramConfig)) {
paramConfig = _.clone(paramConfig);
_.extend(paramConfig, extension);
} else {
paramConfig = extension;
}
}
js = js + JSON.stringify(paramConfig) + '; ';
return js;
};
/**
* Creates a js snippet wich adds or modifies app.common.config
* @method function
* @param {Object} options
* @return {Object} Promise resolved with a stringified js snippet
*/
var createConfig = function(options) {
var configPromise;
var inmediateConfig;
var js = 'window.app = window.app || {}; ';
js = js + 'window.app.common = window.app.common || {}; ';
js = js + 'window.app.common.config = window.app.common.config || {}; ';
options.countries = orderCountries(worldCountries);
// Set debug mode
configLog.debug = (options.debug === 'true');
// Add appName, version, clientType, compatibility, analyticsID
inmediateConfig = ['appName', 'version', 'clientType', 'compatibility', 'analyticsID', 'countries'];
for (var i in inmediateConfig) {
js = js + addToConfig(options, inmediateConfig[i]);
}
// Build backend config
js = js + buildBackendConfig(options);
// Build webfs config
js = js + addToConfig(options, 'webfs');
// Build smartBanner config
configPromise = new Promise(function(resolve) {
buildSmartBannerConfig(options)
.then(function(res) {
js = js + res;
resolve(js);
})
.catch(function(err) {
configLog.warning('SmartBanner config error: ' + err);
resolve(js);
});
});
return configPromise;
};
/**
* Extend default config file with env config file (if exists)
* @method function
*/
var extendConfigFile = function() {
var projectEnvConfig;
try {
projectEnvConfig = requireDir(path.resolve(config.paths.app + '/resources/config/' + buildEnv));
// Try to access config object to check if config.json exists
Object.keys(projectEnvConfig.config);
projectEnvConfig = projectEnvConfig.config;
configLog.info('Using ' + buildEnv + ' config.json');
} catch (err) {
if (err.code !== 'ENOENT') {
// Provide feedback when env file exists but it has errors (e.g. Syntax Error)
configLog.error('Error in ' + buildEnv + ' config.json: ' + err);
}
configLog.info('No env configuration provided. Using default config.json (DEV mode)');
return;
}
_.each(projectEnvConfig, function(value, key) {
_.extend(projectConfig.config[key], value);
});
};
/**
* Get versions specified in config file
* from bower.json files
* & backend version
* @return {[type]} [description]
*/
var getVersions = function() {
var backendConfig = projectConfig.config.backend;
_.extend(backendConfig, _customUrl());
var project = requireDir(path.resolve(''));
var librariesToCheck = projectConfig.config.versions;
var library;
var bowerComponentLibraryFolder;
var versions = {
main: project.bower.version,
composr: {
urlBase: backendConfig.urlBase,
version: backendConfig.version,
domain: backendConfig.domain
}
};
for (var i in librariesToCheck) {
library = librariesToCheck[i];
bowerComponentLibraryFolder = requireDir(path.resolve('bower_components/' + library));
versions[library] = bowerComponentLibraryFolder.bower.version;
}
return JSON.stringify(versions);
};
gulp.task('_environment', function() {
if (!projectConfig.config) {
configLog.error('No config.json provided');
return;
}
extendConfigFile();
var config = createConfig(projectConfig.config);
initDirs();
// Create config.js tmp file
// Adds or modify app namespace
// Access to the custom config in app.common.config
config.then(function(res) {
var versions = getVersions();
fs.writeFile(projectConfigDir + '/config.js', res);
fs.writeFile(distFolder + '/versions.json', versions);
});
});
};