aboutsummaryrefslogtreecommitdiffstats
path: root/library/moment/tasks
diff options
context:
space:
mode:
Diffstat (limited to 'library/moment/tasks')
-rw-r--r--library/moment/tasks/bump_version.js65
-rw-r--r--library/moment/tasks/check_sauce_creds.js13
-rw-r--r--library/moment/tasks/component.js10
-rw-r--r--library/moment/tasks/embed_locales.js47
-rw-r--r--library/moment/tasks/history.js123
-rw-r--r--library/moment/tasks/nuget.js29
-rw-r--r--library/moment/tasks/qtest.js46
-rw-r--r--library/moment/tasks/size.js59
-rw-r--r--library/moment/tasks/transpile.js284
-rw-r--r--library/moment/tasks/update_index.js16
-rw-r--r--library/moment/tasks/zones.js70
11 files changed, 762 insertions, 0 deletions
diff --git a/library/moment/tasks/bump_version.js b/library/moment/tasks/bump_version.js
new file mode 100644
index 000000000..f3dea3106
--- /dev/null
+++ b/library/moment/tasks/bump_version.js
@@ -0,0 +1,65 @@
+module.exports = function (grunt) {
+ grunt.registerTask('bump_version', function (version) {
+ if (!version || version.split('.').length !== 3) {
+ grunt.fail.fatal('malformed version. Use\n\n grunt bump_version:1.2.3');
+ }
+
+ grunt.config('string-replace.moment-js', {
+ files: {'src/moment.js': 'src/moment.js'},
+ options: {
+ replacements: [
+ {
+ pattern: /\/\/! version : .*/,
+ replacement: '//! version : ' + version
+ }, {
+ pattern: /moment\.version = '.*'/,
+ replacement: "moment.version = '" + version + "'"
+ }
+ ]
+ }
+ });
+
+ grunt.config('string-replace.package-json', {
+ files: {'package.json': 'package.json'},
+ options: {
+ replacements: [
+ {
+ pattern: /"version": .*/,
+ replacement: '"version": "' + version + '",'
+ }
+ ]
+ }
+ });
+
+ grunt.config('string-replace.component-json', {
+ files: {'component.json': 'component.json'},
+ options: {
+ replacements: [
+ {
+ pattern: /"version": .*/,
+ replacement: '"version": "' + version + '",'
+ }
+ ]
+ }
+ });
+
+ grunt.config('string-replace.moment-js-nuspec', {
+ files: {'Moment.js.nuspec': 'Moment.js.nuspec'},
+ options: {
+ replacements: [
+ {
+ pattern: /<version>.*<\/version>/,
+ replacement: '<version>' + version + '</version>'
+ }
+ ]
+ }
+ });
+
+ grunt.task.run([
+ 'string-replace:moment-js',
+ 'string-replace:package-json',
+ 'string-replace:component-json',
+ 'string-replace:moment-js-nuspec'
+ ]);
+ });
+};
diff --git a/library/moment/tasks/check_sauce_creds.js b/library/moment/tasks/check_sauce_creds.js
new file mode 100644
index 000000000..e56951d47
--- /dev/null
+++ b/library/moment/tasks/check_sauce_creds.js
@@ -0,0 +1,13 @@
+module.exports = function (grunt) {
+ // Pull requests do not have secure variables enabled for security reasons.
+ // Use this task before launching travis-sauce-browser task, so it would
+ // exit early and won't try connecting to SauceLabs without credentials.
+ grunt.registerTask('check-sauce-creds', function () {
+ if (process.env.SAUCE_USERNAME === undefined) {
+ grunt.log.writeln('No sauce credentials found');
+ grunt.task.clearQueue();
+ } else {
+ grunt.log.writeln('Sauce credentials found');
+ }
+ });
+};
diff --git a/library/moment/tasks/component.js b/library/moment/tasks/component.js
new file mode 100644
index 000000000..f9398aead
--- /dev/null
+++ b/library/moment/tasks/component.js
@@ -0,0 +1,10 @@
+module.exports = function (grunt) {
+ grunt.registerTask('component', function () {
+ var config = JSON.parse(grunt.file.read('component.json'));
+
+ config.files = grunt.file.expand('locale/*.js');
+ config.files.unshift('moment.js');
+
+ grunt.file.write('component.json', JSON.stringify(config, true, 2) + '\n');
+ });
+};
diff --git a/library/moment/tasks/embed_locales.js b/library/moment/tasks/embed_locales.js
new file mode 100644
index 000000000..5027af10c
--- /dev/null
+++ b/library/moment/tasks/embed_locales.js
@@ -0,0 +1,47 @@
+
+module.exports = function (grunt) {
+ grunt.registerTask('embedLocales', function () {
+ var config = grunt.config('embedLocales');
+
+ var files = grunt.file.expand(config.targetLocales);
+ var embeddedContents = determineEmbeddedContent(files);
+
+ var momentContents = grunt.file.read(config.moment);
+ var modifiedContents = momentContents.replace('/* EMBED_LOCALES */', function () {
+ // If we don't do this, $ symbols in locale files may get interpreted in
+ // the regex replacement
+ return embeddedContents;
+ });
+
+ grunt.file.write(config.dest, modifiedContents);
+ });
+
+ var languageReset = 'moment.locale(\'en\');';
+
+ function determineEmbeddedContent(files) {
+ var embeddedContent = '';
+ files.forEach(function (file) {
+ embeddedContent += transformFile(file);
+ });
+ embeddedContent += '\n ' + languageReset + '\n';
+ return embeddedContent;
+ }
+
+ var reTransform = /function \(factory\) \{[^]*\}(?=\(function \(moment\) \{)/gm;
+ var replaceWith =
+ 'function (factory) {\n' +
+ ' factory(moment);\n' +
+ '}';
+
+ function transformFile(file) {
+ var fileContents = grunt.file.read(file);
+
+ if (!fileContents.match(reTransform)) {
+ grunt.warn('Warning: all locale files must use the common UMD wrapper pattern. Failed locale file: ' + file);
+ return '';
+ }
+
+ return fileContents.replace(reTransform, replaceWith);
+ }
+};
+
diff --git a/library/moment/tasks/history.js b/library/moment/tasks/history.js
new file mode 100644
index 000000000..85e83338f
--- /dev/null
+++ b/library/moment/tasks/history.js
@@ -0,0 +1,123 @@
+var https = require('https'),
+ zlib = require('zlib'),
+ path = require('path'),
+ fs = require('fs');
+
+var count = 0;
+var resolved = 0;
+
+var outputs = [];
+
+var done;
+
+function check() {
+ if (resolved === count) {
+ normalize();
+ display();
+ }
+}
+
+function makeBar(length) {
+ var i = '';
+ while (i.length < length) {
+ i += '=';
+ }
+ return i;
+}
+
+function normalize() {
+ var i,
+ max = 0,
+ max2 = 0;
+ for (i = 0; i < count; i++) {
+ max = Math.max(max, outputs[i].gzip);
+ max2 = Math.max(max2, outputs[i].original);
+ }
+ for (i = 0; i < count; i++) {
+ outputs[i].bargraph = makeBar((outputs[i].gzip / max) * 80);
+ outputs[i].bargraph2 = makeBar((outputs[i].original / max2) * 80);
+ }
+}
+
+function display() {
+ var i;
+ for (i = 0; i < count; i++) {
+ console.log(outputs[i].version + ' ' + outputs[i].gzip + ' ' + outputs[i].original);
+ console.log('gzip ' + outputs[i].bargraph);
+ console.log('orig ' + outputs[i].bargraph2);
+ }
+ done();
+}
+
+function getSizeAtVersion(version, path) {
+ var data = '',
+ op = {},
+
+ req = https.request({
+ host: 'raw.github.com',
+ port: 443,
+ path: '/timrwood/moment/' + version + path
+ }, function (res) {
+ res.setEncoding('utf8');
+ res.on('data', function (chunk) {
+ data += chunk;
+ });
+ res.on('end', function (e) {
+ zlib.gzip(data, function (error, result) {
+ op.version = version;
+ op.gzip = result.length;
+ op.original = data.length;
+ resolved++;
+ check();
+ });
+ });
+ });
+
+ req.on('error', function (e) {
+ console.log('problem with request: ' + e.message);
+ });
+ req.end();
+ count++;
+ outputs.push(op);
+}
+
+function getRemote() {
+ var oldVersions = '1.0.1 1.1.0 1.1.1 1.1.2 1.2.0 1.3.0 1.4.0'.split(' '),
+ newVersions = '1.5.0 1.5.1 1.6.0 1.6.1 1.7.0 1.7.1'.split(' '),
+ i;
+
+ for (i = 0; i < oldVersions.length; i++) {
+ getSizeAtVersion(oldVersions[i], '/moment.min.js');
+ }
+ for (i = 0; i < newVersions.length; i++) {
+ getSizeAtVersion(newVersions[i], '/min/moment.min.js');
+ }
+}
+
+function getLocal() {
+ count++;
+ var op = {};
+ outputs.push(op);
+ fs.readFile(path.normalize(__dirname + '/../min/moment.min.js'), 'utf8', function (err, data) {
+ if (err) {
+ throw err;
+ }
+ zlib.gzip(data, function (error, result) {
+ op.version = '.next';
+ op.gzip = result.length;
+ op.original = data.length;
+ resolved++;
+ check();
+ });
+ });
+}
+
+
+
+module.exports = function (grunt) {
+ grunt.registerTask('history', 'Check the codebase filesize over different releases.', function () {
+ done = this.async();
+ getRemote();
+ getLocal();
+ });
+};
diff --git a/library/moment/tasks/nuget.js b/library/moment/tasks/nuget.js
new file mode 100644
index 000000000..7827b2400
--- /dev/null
+++ b/library/moment/tasks/nuget.js
@@ -0,0 +1,29 @@
+module.exports = function (grunt) {
+ // If this fails you might need to follow:
+ //
+ // http://stackoverflow.com/questions/15181888/nuget-on-linux-error-getting-response-stream
+ //
+ // $ sudo mozroots --import --machine --sync
+ // $ sudo certmgr -ssl -m https://go.microsoft.com
+ // $ sudo certmgr -ssl -m https://nugetgallery.blob.core.windows.net
+ // $ sudo certmgr -ssl -m https://nuget.org
+
+ grunt.config('nugetpack', {
+ dist: {
+ src: 'Moment.js.nuspec',
+ dest: './'
+ }
+ });
+ grunt.config('nugetpush', {
+ dist: {
+ src: 'Moment.js.*.nupkg'
+ }
+ });
+ grunt.config('clean.nuget', {
+ src: 'Moment.js.*.nupkg'
+ });
+
+ grunt.registerTask('nuget-publish', [
+ 'nugetpack', 'nugetpush', 'clean:nuget'
+ ]);
+};
diff --git a/library/moment/tasks/qtest.js b/library/moment/tasks/qtest.js
new file mode 100644
index 000000000..ab925321b
--- /dev/null
+++ b/library/moment/tasks/qtest.js
@@ -0,0 +1,46 @@
+module.exports = function (grunt) {
+ grunt.task.registerTask('qtest', 'run tests locally', function () {
+ var done = this.async();
+
+ var testrunner = require('qunit');
+
+ testrunner.options.log.assertions = false;
+ testrunner.options.log.tests = false;
+ testrunner.options.log.summary = false;
+ testrunner.options.log.testing = false;
+ testrunner.options.maxBlockDuration = 120000;
+
+ var tests;
+
+ if (grunt.option('only') != null) {
+ tests = grunt.file.expand.apply(null, grunt.option('only').split(',').map(function (file) {
+ if (file === 'moment') {
+ return 'build/umd/test/moment/*.js';
+ } else if (file === 'locale') {
+ return 'build/umd/test/locale/*.js';
+ } else {
+ return 'build/umd/test/' + file + '.js';
+ }
+ }));
+ } else {
+ tests = grunt.file.expand('build/umd/test/moment/*.js',
+ 'build/umd/test/locale/*.js');
+ }
+
+ testrunner.run({
+ code: 'build/umd/moment.js',
+ tests: tests
+ }, function (err, report) {
+ if (err) {
+ console.log('woot', err, report);
+ done(err);
+ return;
+ }
+ err = null;
+ if (report.failed !== 0) {
+ err = new Error(report.failed + ' tests failed');
+ }
+ done(err);
+ });
+ });
+};
diff --git a/library/moment/tasks/size.js b/library/moment/tasks/size.js
new file mode 100644
index 000000000..2ab380e9f
--- /dev/null
+++ b/library/moment/tasks/size.js
@@ -0,0 +1,59 @@
+var https = require('https'),
+ zlib = require('zlib'),
+ path = require('path'),
+ fs = require('fs');
+
+var stable = '1.7.1',
+ done;
+
+function getVersion(path, cb) {
+ var data = '',
+ req = https.request({
+ host: 'raw.github.com',
+ port: 443,
+ path: '/timrwood/moment/' + path
+ }, function (res) {
+ res.setEncoding('utf8');
+ res.on('data', function (chunk) {
+ data += chunk;
+ });
+ res.on('end', function (e) {
+ zlib.gzip(data, function (error, result) {
+ cb(data.length, result.length);
+ });
+ });
+ });
+ req.on('error', function (e) {
+ console.log('problem with request: ' + e.message);
+ });
+ req.end();
+}
+
+function printDiffs(stableLen, stableGzip, currentLen, currentGzip) {
+ var diff = currentLen - stableLen,
+ gzipDiff = currentGzip - stableGzip;
+
+ console.log('Filesize difference from current branch to ' + stable);
+ console.log(stable + ' ' + stableLen + ' / ' + stableGzip);
+ console.log('curr ' + currentLen + ' / ' + currentGzip);
+ console.log('diff ' + (diff > 0 ? '+' : '') + diff);
+ console.log('gzip ' + (gzipDiff > 0 ? '+' : '') + gzipDiff);
+}
+
+
+module.exports = function (grunt) {
+ grunt.registerTask('size', 'Check the codebase filesize against the latest stable version.', function () {
+ done = this.async();
+ fs.readFile(path.normalize(__dirname + '/../min/moment.min.js'), 'utf8', function (err, data) {
+ if (err) {
+ throw err;
+ }
+ zlib.gzip(data, function (error, result) {
+ getVersion(stable + '/min/moment.min.js', function (stableLength, stableGzipLength) {
+ printDiffs(stableLength, stableGzipLength, data.length, result.length);
+ done();
+ });
+ });
+ });
+ });
+};
diff --git a/library/moment/tasks/transpile.js b/library/moment/tasks/transpile.js
new file mode 100644
index 000000000..d253407d1
--- /dev/null
+++ b/library/moment/tasks/transpile.js
@@ -0,0 +1,284 @@
+module.exports = function (grunt) {
+ var esperanto = require('esperanto');
+ var path = require('path');
+ var Promise = require('es6-promise').Promise;
+ var TMP_DIR = 'build/tmp';
+
+ function moveComments(code) {
+ var comments = [], rest = [];
+ code.split('\n').forEach(function (line) {
+ if (line.trim().slice(0, 3) === '//!') {
+ comments.push(line.trim());
+ } else {
+ rest.push(line);
+ }
+ });
+
+ return comments.concat([''], rest).join('\n');
+ }
+
+ var headerCache = {};
+ function getHeaderByFile(headerFile) {
+ if (!(headerFile in headerCache)) {
+ headerCache[headerFile] = grunt.file.read(headerFile);
+ }
+ return headerCache[headerFile];
+ }
+
+ function transpile(opts) {
+ // base, entry, skip, headerFile, skipLines, target
+ var umdName = opts.headerFile ? 'not_used' : opts.umdName,
+ header = opts.headerFile ? getHeaderByFile(opts.headerFile) : '',
+ skipLines = opts.skipLines ? opts.skipLines : 0;
+
+ return esperanto.bundle({
+ base: opts.base,
+ entry: opts.entry,
+ skip: opts.skip || []
+ }).then(function (bundle) {
+ var umd = bundle.toUmd({name: umdName}),
+ fixed = header + umd.code.split('\n').slice(skipLines).join('\n');
+ if (opts.moveComments) {
+ fixed = moveComments(fixed);
+ }
+ grunt.file.write(opts.target, fixed);
+ });
+ }
+
+ function transpileMany(opts) {
+ var batchSize = 50,
+ promise = Promise.resolve(null),
+ files = grunt.file.expand({cwd: opts.base}, opts.pattern),
+ i,
+ transpileOne = function (i) {
+ promise = promise.then(function () {
+ return Promise.all(files.slice(i, i + batchSize).map(function (file) {
+ return transpile({
+ base: opts.base,
+ entry: file,
+ headerFile: opts.headerFile,
+ skip: opts.skip,
+ skipLines: opts.skipLines,
+ moveComments: opts.moveComments,
+ target: path.join(opts.targetDir, file)
+ });
+ }));
+ });
+ };
+
+ for (i = 0; i < files.length; i += batchSize) {
+ transpileOne(i);
+ }
+
+ return promise;
+ }
+
+ function prepareTemp(base) {
+ var files = grunt.file.expand({cwd: base}, '**/*.js'),
+ tmpDir = TMP_DIR;
+ if (grunt.file.exists(tmpDir)) {
+ return;
+ }
+ files.forEach(function (file) {
+ grunt.file.copy(path.join(base, file), path.join(tmpDir, file));
+ });
+ }
+
+ function transpileCode(opts) {
+ var entry = opts.entry || path.basename(opts.target);
+ prepareTemp(opts.base);
+ grunt.file.write(path.join(TMP_DIR, entry), opts.code);
+ return transpile({
+ base: TMP_DIR,
+ entry: entry,
+ umdName: opts.umdName || 'not_used',
+ headerFile: opts.headerFile,
+ skipLines: opts.skipLines,
+ moveComments: opts.moveComments,
+ target: opts.target,
+ skip: opts.skip
+ });
+ }
+
+ function generateLocales(target, localeFiles) {
+ var files = localeFiles,
+ code = files.map(function (file) {
+ var identifier = path.basename(file, '.js').replace('-', '_');
+ return 'import ' + identifier + ' from "./' + file + '";';
+ }).join('\n');
+ return transpileCode({
+ base: 'src',
+ code: code,
+ target: target,
+ skip: ['moment'],
+ headerFile: 'templates/locale-header.js',
+ skipLines: 5
+ });
+ }
+
+ function generateMomentWithLocales(target, localeFiles) {
+ var files = localeFiles,
+ importCode = files.map(function (file) {
+ var identifier = path.basename(file, '.js').replace('-', '_');
+ var fileNoExt = file.replace('.js', '');
+ return 'import ' + identifier + ' from "./' + fileNoExt + '";';
+ }).join('\n'),
+ code = 'import * as moment_export from "./moment";\n\n' +
+ importCode + '\n\n' +
+ 'export default moment_export;';
+
+ return transpileCode({
+ base: 'src',
+ code: code,
+ umdName: 'moment',
+ target: target
+ }).then(function () {
+ var code = grunt.file.read(target);
+ var getDefaultRegExp = new RegExp('var ([a-z$_]+) =\\s+{[^]\\s+get default \\(\\) { return ([a-z$_]+); }[^]\\s+}', '');
+ var crap = code.match(getDefaultRegExp);
+ if (crap.length !== 3) {
+ grunt.file.write('/tmp/crap.js', code);
+ throw new Error('Failed to detect get default crap, check /tmp/crap.js');
+ }
+ code = code.replace(getDefaultRegExp, '');
+
+ var buildExportVars = ['moment_with_locales', 'moment_with_locales_custom'];
+ buildExportVars.forEach(function (buildExportVar) {
+ var languageReset = buildExportVar + '.locale(\'en\');';
+ code = code.replace('var ' + buildExportVar + ' = ' + crap[1] + ';',
+ 'var ' + buildExportVar + ' = ' + crap[2] + ';\n' +
+ ' ' + languageReset);
+ });
+
+ if (code.match('get default')) {
+ grunt.file.write('/tmp/crap.js', code);
+ throw new Error('Stupid shit es6 get default plaguing the code, check /tmp/crap.js');
+ }
+ grunt.file.write(target, code);
+ });
+ }
+
+ grunt.task.registerTask('transpile-raw', 'convert es6 to umd', function () {
+ var done = this.async();
+
+ transpile({
+ base: 'src',
+ entry: 'moment.js',
+ umdName: 'moment',
+ target: 'build/umd/moment.js',
+ moveComments: true
+ }).then(function () {
+ grunt.log.ok('build/umd/moment.js');
+ }).then(function () {
+ return transpileMany({
+ base: 'src',
+ pattern: 'locale/*.js',
+ headerFile: 'templates/locale-header.js',
+ skipLines: 5,
+ moveComments: true,
+ targetDir: 'build/umd',
+ skip: ['moment']
+ });
+ }).then(function () {
+ grunt.log.ok('build/umd/locale/*.js');
+ }).then(function () {
+ return transpileMany({
+ base: 'src',
+ pattern: 'test/moment/*.js',
+ headerFile: 'templates/test-header.js',
+ skipLines: 5,
+ moveComments: true,
+ targetDir: 'build/umd',
+ skip: ['moment']
+ });
+ }).then(function () {
+ grunt.log.ok('build/umd/test/moment/*.js');
+ }).then(function () {
+ return transpileMany({
+ base: 'src',
+ pattern: 'test/locale/*.js',
+ headerFile: 'templates/test-header.js',
+ skipLines: 5,
+ moveComments: true,
+ targetDir: 'build/umd',
+ skip: ['moment']
+ });
+ }).then(function () {
+ grunt.log.ok('build/umd/test/locale/*.js');
+ }).then(function () {
+ return generateLocales('build/umd/min/locales.js',
+ grunt.file.expand({cwd: 'src'}, 'locale/*.js'));
+ }).then(function () {
+ grunt.log.ok('build/umd/min/locales.js');
+ }).then(function () {
+ return generateMomentWithLocales('build/umd/min/moment-with-locales.js',
+ grunt.file.expand({cwd: 'src'}, 'locale/*.js'));
+ }).then(function () {
+ grunt.log.ok('build/umd/min/moment-with-locales.js');
+ }).then(done, function (e) {
+ grunt.log.error('error transpiling', e);
+ done(e);
+ });
+ });
+
+ grunt.task.registerTask('transpile-custom-raw',
+ 'build just custom language bundles',
+ function (locales) {
+ var done = this.async();
+
+ var localeFiles = locales.split(',').map(function (locale) {
+ var file = grunt.file.expand({cwd: 'src'}, 'locale/' + locale + '.js');
+ if (file.length !== 1) {
+ // we failed to find a locale
+ done(new Error('could not find locale: ' + locale));
+ done = null;
+ } else {
+ return file[0];
+ }
+ });
+
+ // There was an issue with a locale
+ if (done == null) {
+ return;
+ }
+
+ return generateLocales(
+ 'build/umd/min/locales.custom.js', localeFiles
+ ).then(function () {
+ grunt.log.ok('build/umd/min/locales.custom.js');
+ }).then(function () {
+ return generateMomentWithLocales('build/umd/min/moment-with-locales.custom.js',
+ localeFiles);
+ }).then(function () {
+ grunt.log.ok('build/umd/min/moment-with-locales.custom.js');
+ }).then(done, function (e) {
+ grunt.log.error('error transpiling-custom', e);
+ done(e);
+ });
+ });
+
+ grunt.config('clean.build', [
+ 'build'
+ ]);
+
+ grunt.config('concat.tests', {
+ src: 'build/umd/test/**/*.js',
+ dest: 'build/umd/min/tests.js'
+ });
+
+ grunt.task.registerTask('transpile',
+ 'builds all es5 files, optinally creating custom locales',
+ function (locales) {
+ var tasks = [
+ 'clean:build',
+ 'transpile-raw',
+ 'concat:tests'
+ ];
+
+ if (locales) {
+ tasks.push('transpile-custom-raw:' + locales);
+ }
+
+ grunt.task.run(tasks);
+ });
+};
diff --git a/library/moment/tasks/update_index.js b/library/moment/tasks/update_index.js
new file mode 100644
index 000000000..c866e2694
--- /dev/null
+++ b/library/moment/tasks/update_index.js
@@ -0,0 +1,16 @@
+module.exports = function (grunt) {
+ grunt.config('copy.index-files', {
+ expand: true,
+ cwd: 'build/umd/',
+ src: [
+ 'moment.js',
+ 'locale/*.js',
+ 'min/locales.js',
+ 'min/moment-with-locales.js',
+ 'min/tests.js'
+ ],
+ dest: '.'
+ });
+
+ grunt.registerTask('update-index', ['copy:index-files']);
+};
diff --git a/library/moment/tasks/zones.js b/library/moment/tasks/zones.js
new file mode 100644
index 000000000..7aa88b1f6
--- /dev/null
+++ b/library/moment/tasks/zones.js
@@ -0,0 +1,70 @@
+var fs = require('fs');
+
+
+module.exports = function (grunt) {
+ var ZONE_TAB = '/usr/share/zoneinfo/zone.tab';
+
+ grunt.registerTask('zones', 'Run the unit tests in different timezones.', function () {
+ var done = this.async();
+
+ getAllTimezones(function (err, zones) {
+ if (err != null) {
+ throw err;
+ }
+ (function iterator(i) {
+ if (i >= zones.length) {
+ return done();
+ }
+ runTestsInZone(zones[i], function (err) {
+ if (err != null) {
+ throw err;
+ }
+ iterator(i + 1);
+ });
+ }(0));
+ });
+ });
+
+ function getAllTimezones (callback) {
+ fs.readFile(ZONE_TAB, 'ascii', function (err, content) {
+ if (err != null) {
+ callback(err);
+ }
+ callback(null, content.split(/\r\n|\r|\n/)
+ // remove empty and commented lines
+ .filter(function (line) {
+ return line && !/^#/.test(line);
+ })
+ // country code TAB coordinates TAB timezone
+ .map(function (line) {
+ return line.split('\t')[2];
+ }));
+ });
+ }
+
+ function runTestsInZone (zone, next) {
+ grunt.log.ok('Running tests in zone ' + zone);
+ grunt.util.spawn({
+ cmd: 'grunt',
+ opts: {
+ env: {
+ 'PATH': process.env.PATH,
+ 'TZ': zone
+ }
+ },
+ args: ['--no-color', 'nodeunit']
+ }, function (err, result, code) {
+ if (code !== 0) {
+ grunt.log.error(result.stdout.split(/\r\n|\r|\n/)
+ .filter(function (line) {
+ return /^(>>|Warning:|$)/.test(line);
+ })
+ .map(function (line) {
+ return (line.substr(0, 3) === '>> ' ? line.substr(3) : line);
+ })
+ .join('\n'));
+ }
+ next();
+ });
+ }
+};