2017-11-12 03:59:09 +03:00
|
|
|
// Initialize requirements
|
2014-08-04 17:53:18 +04:00
|
|
|
var fs = require('fs'),
|
2014-08-06 16:08:19 +04:00
|
|
|
https = require('https'),
|
|
|
|
exec = require('child_process').exec,
|
2014-08-04 17:53:18 +04:00
|
|
|
eventStream = require('event-stream'),
|
2021-01-29 19:54:44 +03:00
|
|
|
runSequence = require('gulp4-run-sequence'),
|
2014-08-13 16:14:35 +04:00
|
|
|
through = require('through2'),
|
|
|
|
lodash = require('lodash'),
|
|
|
|
PoFile = require('pofile'),
|
|
|
|
strftime = require('strftime'),
|
2015-03-31 13:54:34 +03:00
|
|
|
del = require('del'),
|
2015-03-23 19:42:32 +03:00
|
|
|
bower = require('bower'),
|
2014-08-04 17:53:18 +04:00
|
|
|
gulp = require('gulp'),
|
|
|
|
uglify = require('gulp-uglify'),
|
|
|
|
concat = require('gulp-concat'),
|
|
|
|
phpcs = require('gulp-phpcs'),
|
|
|
|
order = require('gulp-order'),
|
|
|
|
handlebars = require('gulp-handlebars'),
|
2014-09-15 18:32:34 +04:00
|
|
|
handlebarsEngine = require('handlebars'),
|
2014-08-04 17:53:18 +04:00
|
|
|
defineModule = require('gulp-define-module'),
|
2014-08-07 15:04:45 +04:00
|
|
|
header = require('gulp-header'),
|
|
|
|
zip = require('gulp-zip'),
|
|
|
|
tar = require('gulp-tar'),
|
|
|
|
gzip = require('gulp-gzip'),
|
2014-08-13 12:40:42 +04:00
|
|
|
chmod = require('gulp-chmod'),
|
|
|
|
xgettext = require('gulp-xgettext'),
|
2015-03-23 19:42:32 +03:00
|
|
|
concatPo = require('gulp-concat-po'),
|
2016-05-30 16:15:50 +03:00
|
|
|
rename = require('gulp-rename'),
|
2017-11-11 02:44:40 +03:00
|
|
|
eslint = require('gulp-eslint'),
|
2017-11-28 17:14:46 +03:00
|
|
|
removeDuplicateHeaders = require('mibew-gulp-greh'),
|
2017-11-11 02:44:40 +03:00
|
|
|
mkdirp = require('mkdirp');
|
2014-08-04 17:53:18 +04:00
|
|
|
|
2017-11-12 03:59:09 +03:00
|
|
|
// Set global configuration
|
2014-08-04 17:53:18 +04:00
|
|
|
var config = {
|
|
|
|
mibewPath: 'mibew',
|
2014-09-26 17:18:42 +04:00
|
|
|
configsPath: 'mibew/configs',
|
2014-08-04 17:53:18 +04:00
|
|
|
phpVendorPath: 'mibew/vendor',
|
2015-03-23 19:42:32 +03:00
|
|
|
jsVendorPath: 'mibew/js/vendor',
|
2014-08-04 17:53:18 +04:00
|
|
|
pluginsPath: 'mibew/plugins',
|
2014-09-26 17:18:42 +04:00
|
|
|
avatarsPath: 'mibew/files/avatar',
|
2014-09-24 17:04:37 +04:00
|
|
|
cachePath: 'mibew/cache',
|
2014-08-04 17:53:18 +04:00
|
|
|
jsPath: 'mibew/js',
|
2014-10-13 17:52:17 +04:00
|
|
|
chatStylesPath: 'mibew/styles/chats',
|
2014-08-04 17:53:18 +04:00
|
|
|
pageStylesPath: 'mibew/styles/pages',
|
2017-11-11 02:44:40 +03:00
|
|
|
i18nPath: 'i18n',
|
|
|
|
i18nPrefix: 'mibew-i18n-',
|
|
|
|
releasePath: 'release',
|
2017-11-12 02:20:45 +03:00
|
|
|
uploadPath: 'upload',
|
2014-08-06 16:08:19 +04:00
|
|
|
compiledTemplatesHeader: fs.readFileSync('tools/compiled_templates_header.txt'),
|
2014-08-07 15:04:45 +04:00
|
|
|
getComposerUrl: 'https://getcomposer.org/installer',
|
2017-11-10 15:52:05 +03:00
|
|
|
phpBin: 'php -d "suhosin.executor.include.whitelist = phar" -d "memory_limit=512M"',
|
2017-11-11 02:44:40 +03:00
|
|
|
package: require('./composer.json'),
|
|
|
|
msginit: 'msginit',
|
|
|
|
msgcat: 'msgcat'
|
2014-08-04 17:53:18 +04:00
|
|
|
}
|
2017-11-11 02:44:40 +03:00
|
|
|
config.i18nSuffix = '-' + config.package.version + '-' + strftime('%Y%m%d');
|
2014-08-04 17:53:18 +04:00
|
|
|
|
2017-11-12 03:59:09 +03:00
|
|
|
// Tasks for cleaning //////////////////
|
|
|
|
|
2015-03-31 13:54:34 +03:00
|
|
|
// Cleans all built files
|
|
|
|
gulp.task('clean', function(callback) {
|
2021-01-29 19:54:44 +03:00
|
|
|
return del([
|
2017-11-11 02:44:40 +03:00
|
|
|
config.releasePath,
|
2015-03-31 13:54:34 +03:00
|
|
|
'composer.lock',
|
|
|
|
config.phpVendorPath,
|
|
|
|
config.jsVendorPath,
|
2015-04-14 14:43:56 +03:00
|
|
|
config.jsPath + '/compiled/**/*',
|
2015-03-31 13:54:34 +03:00
|
|
|
'!' + config.jsPath + '/compiled/.keep',
|
2017-05-23 17:12:28 +03:00
|
|
|
config.chatStylesPath + '/*/templates_compiled/client_side/*.js',
|
|
|
|
config.chatStylesPath + '/*/js/compiled/*.js',
|
|
|
|
config.pageStylesPath + '/*/templates_compiled/client_side/*.js'
|
2015-03-31 13:54:34 +03:00
|
|
|
], callback);
|
|
|
|
});
|
|
|
|
|
2017-11-12 03:59:09 +03:00
|
|
|
// Cleans temporary English translation in the release dir
|
2021-01-29 19:54:44 +03:00
|
|
|
gulp.task('clean-tmp-po', function(callback) {
|
|
|
|
return del([config.releasePath + '/translation.po'], callback);
|
2017-11-12 03:59:09 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
// Cleans temporary files of translations in the release dir
|
2021-01-29 19:54:44 +03:00
|
|
|
gulp.task('clean-tmp-i18n-files', function(callback) {
|
2017-11-12 03:59:09 +03:00
|
|
|
return del([
|
|
|
|
config.releasePath + '/**/*',
|
|
|
|
'!' + config.releasePath + '/*.zip',
|
|
|
|
'!' + config.releasePath + '/*.tar.gz',
|
|
|
|
'!' + config.releasePath + '/*.pot'
|
2021-01-29 19:54:44 +03:00
|
|
|
], callback);
|
2017-11-12 03:59:09 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
// Cleans all files prepared for uploading to CDN
|
|
|
|
gulp.task('clean-upload', function(callback) {
|
|
|
|
return del([config.uploadPath], callback);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Cleans everything
|
|
|
|
gulp.task('clean-all', function(callback) {
|
|
|
|
runSequence( ['clean', 'clean-upload'],
|
|
|
|
callback );
|
|
|
|
});
|
|
|
|
|
2016-05-30 16:15:50 +03:00
|
|
|
|
2017-11-12 03:59:09 +03:00
|
|
|
// Watcher tasks ///////////////////////
|
|
|
|
|
|
|
|
// Watch styles
|
2021-01-29 19:54:44 +03:00
|
|
|
gulp.task('watch', function() {
|
|
|
|
gulp.watch(config.pageStylesPath + '/**/*.handlebars', gulp.series('page-styles'));
|
|
|
|
gulp.watch(config.chatStylesPath + '/**/js/source/**/*.js', gulp.series('chat-styles-js'));
|
|
|
|
gulp.watch(config.chatStylesPath + '/**/*.handlebars', gulp.series('chat-styles-handlebars'));
|
2017-11-12 03:59:09 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
// Service tasks //////////////////
|
|
|
|
|
2014-08-06 16:08:19 +04:00
|
|
|
// Get and install PHP Composer
|
|
|
|
gulp.task('get-composer', function(callback) {
|
2017-11-12 03:59:09 +03:00
|
|
|
// Check whether Composer is already in place
|
2014-08-06 16:08:19 +04:00
|
|
|
if (fs.existsSync('./composer.phar')) {
|
|
|
|
callback(null);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-11-12 03:59:09 +03:00
|
|
|
// Get installer from the Internet
|
2014-08-06 16:08:19 +04:00
|
|
|
https.get(config.getComposerUrl, function(response) {
|
|
|
|
// Run PHP to install Composer
|
2014-08-12 14:35:57 +04:00
|
|
|
var php = exec(config.phpBin, function(error, stdout, stderr) {
|
2014-08-06 16:08:19 +04:00
|
|
|
callback(error ? stderr : null);
|
|
|
|
});
|
|
|
|
// Pass installer code to PHP via STDIN
|
|
|
|
response.pipe(php.stdin);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
// Install Composer dependencies excluding development ones
|
2021-01-29 19:54:44 +03:00
|
|
|
gulp.task('composer-install', gulp.series('get-composer', function(callback) {
|
2017-11-12 03:59:09 +03:00
|
|
|
exec(config.phpBin + ' composer.phar install --no-dev',
|
|
|
|
function(error, stdout, stderr) {
|
|
|
|
callback(error ? stderr : null);
|
|
|
|
});
|
2021-01-29 19:54:44 +03:00
|
|
|
}));
|
2014-08-06 16:08:19 +04:00
|
|
|
|
|
|
|
// Install all Composer dependencies
|
2021-01-29 19:54:44 +03:00
|
|
|
gulp.task('composer-install-dev', gulp.series('get-composer', function(callback) {
|
2017-11-12 03:59:09 +03:00
|
|
|
exec(config.phpBin + ' composer.phar install',
|
|
|
|
function(error, stdout, stderr) {
|
|
|
|
callback(error ? stderr : null);
|
|
|
|
});
|
2021-01-29 19:54:44 +03:00
|
|
|
}));
|
2014-08-06 16:08:19 +04:00
|
|
|
|
2015-03-23 19:42:32 +03:00
|
|
|
// Installs bower dependencies
|
|
|
|
gulp.task('bower-install', function(callback) {
|
|
|
|
bower.commands.install([], {}, {})
|
|
|
|
.on('error', function(error) {
|
|
|
|
callback(error);
|
|
|
|
})
|
|
|
|
.on('end', function() {
|
|
|
|
// We should manually minify JavaScript files that was not minified
|
2017-11-12 03:59:09 +03:00
|
|
|
// by bower packages' authors
|
2015-03-23 19:42:32 +03:00
|
|
|
// TODO: This is a temproary workaround and should be removed once
|
2017-11-12 03:59:09 +03:00
|
|
|
// the packages will be fixed
|
2015-03-23 19:42:32 +03:00
|
|
|
var stream = eventStream.merge(
|
2017-11-12 03:59:09 +03:00
|
|
|
gulp.src(config.jsVendorPath + '/backbone/backbone.js',
|
|
|
|
{base: config.jsVendorPath})
|
2015-03-23 19:42:32 +03:00
|
|
|
.pipe(uglify({preserveComments: 'some'}))
|
|
|
|
// There are neither "@license" tag nor "!preserve" in the
|
2017-11-12 03:59:09 +03:00
|
|
|
// header. Add the header manually
|
2015-03-23 19:42:32 +03:00
|
|
|
.pipe(header(
|
|
|
|
"// Backbone.js 1.1.2\n"
|
|
|
|
+ "// (c) 2010-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n"
|
|
|
|
+ "// Backbone may be freely distributed under the MIT license.\n"
|
|
|
|
+ "// For all details and documentation:\n"
|
|
|
|
+ "// http://backbonejs.org\n"
|
|
|
|
))
|
|
|
|
.pipe(rename('backbone/backbone-min.js')),
|
2017-11-12 03:59:09 +03:00
|
|
|
gulp.src(config.jsVendorPath + '/json/json2.js',
|
|
|
|
{base: config.jsVendorPath})
|
2015-03-23 19:42:32 +03:00
|
|
|
.pipe(uglify({preserveComments: 'some'}))
|
|
|
|
// There are neither "@license" tag nor "!preserve" in the
|
2017-11-12 03:59:09 +03:00
|
|
|
// header, add the header manually
|
2015-03-23 19:42:32 +03:00
|
|
|
.pipe(header("// json2.js. Public Domain. See http://www.JSON.org/js.html\n"))
|
|
|
|
.pipe(rename('json/json2.min.js'))
|
2015-04-14 14:39:33 +03:00
|
|
|
)
|
|
|
|
.pipe(gulp.dest(config.jsVendorPath));
|
2015-03-23 19:42:32 +03:00
|
|
|
|
|
|
|
stream
|
|
|
|
.on('error', callback)
|
|
|
|
.on('end', callback);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2021-01-29 19:54:44 +03:00
|
|
|
// Tasks for checking //////////////////
|
|
|
|
|
|
|
|
// Checks all PHP files with PHP Code Sniffer
|
|
|
|
gulp.task('phpcs', gulp.series('composer-install-dev', function() {
|
|
|
|
return gulp.src([
|
|
|
|
config.mibewPath + '/**/*.php',
|
|
|
|
'!' + config.phpVendorPath + '/**/*.*',
|
|
|
|
'!' + config.pluginsPath + '/**/*.*',
|
|
|
|
'!' + config.cachePath + '/**/*.*'
|
|
|
|
], {
|
|
|
|
// Content of the cache directory is readable only for webserver.
|
|
|
|
// Thus we must to set "strict" option to false to prevent "EACCES"
|
|
|
|
// errors. At the same we need to see all errors that take place.
|
|
|
|
strict: false,
|
|
|
|
silent: false
|
|
|
|
})
|
|
|
|
.pipe(phpcs({
|
|
|
|
bin: config.phpVendorPath + '/bin/phpcs',
|
|
|
|
standard: 'PSR2',
|
|
|
|
warningSeverity: 0
|
|
|
|
}))
|
|
|
|
.pipe(phpcs.reporter('log'))
|
|
|
|
.pipe(phpcs.reporter('fail'));
|
|
|
|
}));
|
|
|
|
|
|
|
|
// Checks all JavaScript Source files with ESLint
|
|
|
|
gulp.task('eslint', function() {
|
|
|
|
return gulp.src(config.jsPath + '/source/**/*.js')
|
|
|
|
.pipe(eslint())
|
|
|
|
.pipe(eslint.format())
|
|
|
|
.pipe(eslint.failAfterError());
|
|
|
|
});
|
|
|
|
|
|
|
|
|
2017-11-12 03:59:09 +03:00
|
|
|
// Restore empty English translation in the source code
|
|
|
|
gulp.task('post-pack-cleanup', function(callback) {
|
|
|
|
gulp.src('translation.po')
|
|
|
|
.pipe(gulp.dest(config.mibewPath + '/locales/en/'));
|
|
|
|
|
|
|
|
del(['translation.po', config.releasePath + '/translation.po'], callback);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Tasks of compiling //////////////////
|
|
|
|
|
|
|
|
// Compile all JavaScript files of the Mibew Messenger Core
|
2014-08-04 17:53:18 +04:00
|
|
|
gulp.task('js', function() {
|
|
|
|
return eventStream.merge(
|
|
|
|
getClientSideApp('default'),
|
|
|
|
getClientSideApp('chat'),
|
|
|
|
getClientSideApp('thread_log'),
|
|
|
|
getClientSideApp('users'),
|
|
|
|
gulp.src(config.jsPath + '/source/**/*.js')
|
|
|
|
)
|
|
|
|
.pipe(uglify({preserveComments: 'some'}))
|
2017-11-28 17:14:46 +03:00
|
|
|
.pipe(removeDuplicateHeaders())
|
2014-08-04 17:53:18 +04:00
|
|
|
.pipe(gulp.dest(config.jsPath + '/compiled'));
|
|
|
|
});
|
|
|
|
|
2017-11-12 03:59:09 +03:00
|
|
|
// Compile and concatenate Handlebars templates for all chat styles
|
2014-08-04 17:53:18 +04:00
|
|
|
gulp.task('chat-styles-handlebars', function() {
|
2017-03-16 23:46:01 +03:00
|
|
|
return getChildDirs(config.chatStylesPath)
|
|
|
|
.then(function (dirs) {
|
|
|
|
return Promise.all(dirs.map(function (dir) {
|
2017-11-11 02:44:40 +03:00
|
|
|
return new Promise(function(resolve, reject) {
|
2017-11-12 03:59:09 +03:00
|
|
|
gulp.src(config.chatStylesPath + '/' + dir
|
|
|
|
+ '/templates_src/client_side/**/*.handlebars')
|
2017-03-16 23:46:01 +03:00
|
|
|
.pipe(handlebars({
|
|
|
|
// Use specific version of Handlebars.js
|
|
|
|
handlebars: handlebarsEngine
|
|
|
|
}))
|
|
|
|
.pipe(wrapHandlebarsTemplate())
|
|
|
|
.pipe(concat('templates.js'))
|
|
|
|
.pipe(uglify({preserveComments: 'some'}))
|
|
|
|
.pipe(header(config.compiledTemplatesHeader))
|
2017-11-12 03:59:09 +03:00
|
|
|
.pipe(gulp.dest(config.chatStylesPath + '/' + dir
|
|
|
|
+ '/templates_compiled/client_side'))
|
2017-03-16 23:46:01 +03:00
|
|
|
.on('end', resolve)
|
|
|
|
.on('error', reject);
|
|
|
|
});
|
|
|
|
}));
|
2017-03-10 01:44:53 +03:00
|
|
|
});
|
2014-08-04 17:53:18 +04:00
|
|
|
});
|
|
|
|
|
2017-11-12 03:59:09 +03:00
|
|
|
// Compile and concatenate js files for all chat styles
|
2014-08-04 17:53:18 +04:00
|
|
|
gulp.task('chat-styles-js', function() {
|
2017-03-16 23:46:01 +03:00
|
|
|
return getChildDirs(config.chatStylesPath)
|
|
|
|
.then(function (dirs) {
|
|
|
|
return Promise.all(dirs.map(function (dir) {
|
2017-11-11 02:44:40 +03:00
|
|
|
return new Promise(function(resolve, reject) {
|
2017-11-12 03:59:09 +03:00
|
|
|
gulp.src(config.chatStylesPath + '/' + dir
|
|
|
|
+ '/js/source/**/*.js')
|
2017-03-16 23:46:01 +03:00
|
|
|
.pipe(concat('scripts.js'))
|
|
|
|
.pipe(uglify({preserveComments: 'some'}))
|
2017-11-12 03:59:09 +03:00
|
|
|
.pipe(gulp.dest(config.chatStylesPath + '/' + dir
|
|
|
|
+ '/js/compiled'))
|
2017-03-16 23:46:01 +03:00
|
|
|
.on('end', resolve)
|
|
|
|
.on('error', reject);
|
|
|
|
});
|
|
|
|
}));
|
2017-03-10 01:44:53 +03:00
|
|
|
});
|
2014-08-04 17:53:18 +04:00
|
|
|
});
|
|
|
|
|
2017-11-12 03:59:09 +03:00
|
|
|
// Performs all job related to pages styles
|
2014-08-04 17:53:18 +04:00
|
|
|
gulp.task('page-styles', function() {
|
2017-03-16 23:46:01 +03:00
|
|
|
return getChildDirs(config.pageStylesPath)
|
|
|
|
.then(function (dirs) {
|
|
|
|
return Promise.all(dirs.map(function (dir) {
|
|
|
|
return new Promise(function(resolve, reject){
|
2017-11-12 03:59:09 +03:00
|
|
|
gulp.src(config.pageStylesPath + '/' + dir
|
|
|
|
+ '/templates_src/client_side/**/*.handlebars')
|
2017-03-16 23:46:01 +03:00
|
|
|
.pipe(handlebars({
|
|
|
|
// Use specific version of Handlebars.js
|
|
|
|
handlebars: handlebarsEngine
|
|
|
|
}))
|
|
|
|
.pipe(wrapHandlebarsTemplate())
|
|
|
|
.pipe(concat('templates.js'))
|
|
|
|
.pipe(uglify({preserveComments: 'some'}))
|
|
|
|
.pipe(header(config.compiledTemplatesHeader))
|
2017-11-12 03:59:09 +03:00
|
|
|
.pipe(gulp.dest(config.pageStylesPath + '/' + dir
|
|
|
|
+ '/templates_compiled/client_side'))
|
2017-03-16 23:46:01 +03:00
|
|
|
.on('end', resolve)
|
|
|
|
.on('error', reject);
|
|
|
|
});
|
|
|
|
}));
|
2017-03-10 01:44:53 +03:00
|
|
|
});
|
2014-08-04 17:53:18 +04:00
|
|
|
});
|
|
|
|
|
2017-11-12 03:59:09 +03:00
|
|
|
// Performs all job related to chat styles
|
2021-01-29 19:54:44 +03:00
|
|
|
gulp.task('chat-styles', gulp.series('chat-styles-handlebars', 'chat-styles-js'));
|
2017-03-10 01:45:23 +03:00
|
|
|
|
2017-11-12 03:59:09 +03:00
|
|
|
// Prepares ready to use development version of Mibew Messenger without
|
|
|
|
// packing or validating it
|
|
|
|
gulp.task('rebuild', function(callback) {
|
|
|
|
runSequence(
|
|
|
|
'clean',
|
|
|
|
['js', 'chat-styles', 'page-styles', 'composer-install',
|
|
|
|
'bower-install'],
|
|
|
|
callback
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
// Tasks for localization issues ///////
|
|
|
|
|
|
|
|
// Generate POT-file based upon the source code
|
2014-08-13 12:40:42 +04:00
|
|
|
gulp.task('generate-pot', function() {
|
2014-08-13 16:14:35 +04:00
|
|
|
return eventStream.merge(
|
|
|
|
gulp.src([
|
2017-11-12 03:59:09 +03:00
|
|
|
config.mibewPath + '/**/*.php',
|
|
|
|
'!' + config.phpVendorPath + '/**/*.*',
|
|
|
|
'!' + config.pluginsPath + '/**/*.*',
|
|
|
|
'!' + config.cachePath + '/**/*.*'
|
|
|
|
], {
|
|
|
|
// Content of the cache directory is readable only for
|
|
|
|
// webserver. Thus we must to set "strict" option to false
|
|
|
|
// to prevent "EACCES" errors. At the same we need to see all
|
|
|
|
// errors that take place.
|
|
|
|
strict: false,
|
|
|
|
silent: false
|
|
|
|
})
|
2014-08-13 16:14:35 +04:00
|
|
|
.pipe(xgettext({
|
|
|
|
language: 'PHP',
|
|
|
|
keywords: [
|
2014-08-18 13:42:08 +04:00
|
|
|
{name: 'getlocal'},
|
|
|
|
{name: 'no_field'},
|
|
|
|
{name: 'wrong_field'},
|
|
|
|
{name: 'failed_uploading_file', singular: 2}
|
2014-08-13 16:14:35 +04:00
|
|
|
]
|
|
|
|
})),
|
2014-08-18 13:23:15 +04:00
|
|
|
gulp.src(config.jsPath + '/source/**/*.js', {base: config.mibewPath})
|
|
|
|
.pipe(xgettext({
|
|
|
|
language: 'JavaScript',
|
|
|
|
keywords: [
|
|
|
|
{name: 'trans'}
|
|
|
|
]
|
|
|
|
})),
|
2014-08-13 16:14:35 +04:00
|
|
|
gulp.src([
|
2017-11-12 03:59:09 +03:00
|
|
|
config.chatStylesPath + '/default/templates_src/**/*.handlebars',
|
|
|
|
config.pageStylesPath + '/default/templates_src/**/*.handlebars'
|
|
|
|
], {base: config.mibewPath})
|
2014-08-13 16:14:35 +04:00
|
|
|
.pipe(xgettextHandlebars())
|
|
|
|
)
|
2017-11-12 03:59:09 +03:00
|
|
|
.pipe(concatPo(config.i18nPrefix + 'translation'
|
|
|
|
+ config.i18nSuffix + '.pot',
|
|
|
|
{
|
|
|
|
headers: {
|
|
|
|
'Project-Id-Version': 'Mibew Messenger '
|
|
|
|
+ config.package.version,
|
|
|
|
'Report-Msgid-Bugs-To': config.package.support.email,
|
|
|
|
'POT-Creation-Date': strftime('%Y-%m-%d %H:%M%z'),
|
|
|
|
'PO-Revision-Date': '',
|
|
|
|
'Last-Translator': '',
|
|
|
|
'Language-Team': '',
|
|
|
|
'Content-Type': 'text/plain; charset=UTF-8'
|
|
|
|
}
|
|
|
|
})
|
|
|
|
)
|
2017-11-11 02:44:40 +03:00
|
|
|
.pipe(gulp.dest(config.releasePath));
|
|
|
|
});
|
|
|
|
|
2017-11-12 03:59:09 +03:00
|
|
|
// Generate temporary English translation to be used in the release
|
2021-01-29 19:54:44 +03:00
|
|
|
gulp.task('generate-tmp-po', gulp.series('generate-pot', function(callback) {
|
2017-11-12 03:59:09 +03:00
|
|
|
return exec(config.msginit + ' --no-translator --no-wrap -i '
|
|
|
|
+ config.releasePath + '/' + config.i18nPrefix + 'translation'
|
|
|
|
+ config.i18nSuffix + '.pot' + ' -l en -o '
|
|
|
|
+ config.releasePath + '/translation.po',
|
|
|
|
function(error, stdout, stderr) {
|
|
|
|
callback(error ? stderr : null);
|
|
|
|
});
|
2021-01-29 19:54:44 +03:00
|
|
|
}));
|
2017-11-11 02:44:40 +03:00
|
|
|
|
2017-11-12 03:59:09 +03:00
|
|
|
// Generate complete translations (that includes missed strings) to be used
|
|
|
|
// in the release
|
2021-01-29 19:54:44 +03:00
|
|
|
gulp.task('generate-pos', gulp.series('generate-tmp-po', function(callback) {
|
2017-11-11 02:44:40 +03:00
|
|
|
|
|
|
|
return getChildDirs(config.i18nPath + '/translations')
|
|
|
|
.then(function (dirs) {
|
|
|
|
return Promise.all(dirs.map(function (dir) {
|
|
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
mkdirp(config.releasePath + '/' + dir, function (error) {
|
|
|
|
if (error) {
|
|
|
|
reject(error);
|
|
|
|
}
|
|
|
|
});
|
2017-11-12 03:59:09 +03:00
|
|
|
exec(config.msgcat + ' ' + config.i18nPath + '/translations/'
|
|
|
|
+ dir + '/translation.po ' + config.releasePath
|
|
|
|
+ '/translation.po --no-location --no-wrap --use-first'
|
|
|
|
+ ' -o ' + config.releasePath + '/' + dir
|
|
|
|
+ '/translation.po',
|
|
|
|
function(error, stdout, stderr) {
|
|
|
|
if (error) {
|
|
|
|
reject(error);
|
|
|
|
}
|
2017-11-11 02:44:40 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
var sources = [
|
|
|
|
config.i18nPath + '/translations/' + dir + '/**/*',
|
2017-11-12 03:59:09 +03:00
|
|
|
'!' + config.i18nPath + '/translations/' + dir
|
|
|
|
+ '/translation.po'
|
2017-11-11 02:44:40 +03:00
|
|
|
];
|
|
|
|
|
|
|
|
gulp.src(sources)
|
|
|
|
.pipe(gulp.dest(config.releasePath + '/' + dir))
|
|
|
|
.on('error', reject)
|
|
|
|
.on('end', resolve);
|
|
|
|
});
|
|
|
|
}));
|
|
|
|
});
|
2021-01-29 19:54:44 +03:00
|
|
|
}));
|
2017-11-11 02:44:40 +03:00
|
|
|
|
2017-11-12 03:59:09 +03:00
|
|
|
// Packaging tasks /////////////////////
|
2014-08-13 12:40:42 +04:00
|
|
|
|
2017-11-12 03:59:09 +03:00
|
|
|
// Pack sources for release as .zip and .tar.gz archives
|
2021-01-29 19:54:44 +03:00
|
|
|
gulp.task('pack-sources', gulp.series('composer-install', 'bower-install', function() {
|
2017-11-11 02:44:40 +03:00
|
|
|
gulp.src(config.mibewPath + '/locales/en/translation.po')
|
|
|
|
.pipe(gulp.dest('.'));
|
|
|
|
gulp.src(config.releasePath + '/translation.po')
|
|
|
|
.pipe(gulp.dest(config.mibewPath + '/locales/en/'));
|
|
|
|
|
2014-08-13 13:04:44 +04:00
|
|
|
var sources = [
|
|
|
|
config.mibewPath + '/**/*',
|
2014-09-26 17:18:42 +04:00
|
|
|
// Exclude user's config
|
|
|
|
'!' + config.configsPath + '/config.yml',
|
|
|
|
// Exclude cache files but not the ".keep" file.
|
2014-09-24 17:04:37 +04:00
|
|
|
'!' + config.cachePath + '/**/!(.keep)',
|
2014-09-26 17:18:42 +04:00
|
|
|
// Exclude avatars but not the ".keep" file.
|
|
|
|
'!' + config.avatarsPath + '/!(.keep)',
|
|
|
|
// Exclude plugins but not the ".keep" file.
|
|
|
|
'!' + config.pluginsPath + '/!(.keep)',
|
|
|
|
'!' + config.pluginsPath + '/*/**/*',
|
2014-08-13 13:04:44 +04:00
|
|
|
// Exclude Git repositories that can be shipped with third-party libs
|
|
|
|
'!' + config.phpVendorPath + '/**/.git',
|
2014-12-11 17:06:15 +03:00
|
|
|
'!' + config.phpVendorPath + '/**/.git/**/*',
|
|
|
|
// Exclude vendors binaries
|
2014-12-23 17:48:26 +03:00
|
|
|
'!' + config.phpVendorPath + '/bin/**/*',
|
|
|
|
// Exclude JavaScript sources
|
2015-03-23 19:42:32 +03:00
|
|
|
'!' + config.jsPath + '/source/**/*',
|
|
|
|
// Actually we does not need backbone.babysitter and backbone.wreqr
|
|
|
|
// dependencies because they embed into marionette.js. So we exclude
|
|
|
|
// "backbone.babysitter" and "backbone.wreqr" directories and all their
|
|
|
|
// contents.
|
|
|
|
'!' + config.jsVendorPath + '/backbone.babysitter{,/**}',
|
|
|
|
'!' + config.jsVendorPath + '/backbone.wreqr{,/**}',
|
|
|
|
// Exclude dot files within third-party JS libraries.
|
|
|
|
'!' + config.jsVendorPath + '/**/.*',
|
|
|
|
// Exclude config files of various package systems
|
|
|
|
'!' + config.jsVendorPath + '/**/{bower,component,package,composer}.json',
|
|
|
|
// Exclude config files of various build systems
|
|
|
|
'!' + config.jsVendorPath + '/**/Gruntfile.*',
|
|
|
|
'!' + config.jsVendorPath + '/**/gulpfile.*',
|
|
|
|
'!' + config.jsVendorPath + '/**/Makefile',
|
|
|
|
// Exclude HTML files from third-party JS libraries. Such files can be
|
|
|
|
// used for docs or for tests, we need none of them.
|
|
|
|
'!' + config.jsVendorPath + '/**/*.html',
|
|
|
|
// There are too many useless files in Vex.js library. Exclude them.
|
|
|
|
'!' + config.jsVendorPath + '/vex/sass{,/**}',
|
|
|
|
'!' + config.jsVendorPath + '/vex/docs{,/**}',
|
|
|
|
'!' + config.jsVendorPath + '/vex/docs{,/**}',
|
|
|
|
'!' + config.jsVendorPath + '/vex/coffee{,/**}'
|
2014-08-13 13:04:44 +04:00
|
|
|
];
|
2014-09-24 17:04:37 +04:00
|
|
|
var srcOptions = {
|
2017-11-12 03:59:09 +03:00
|
|
|
// Dot files (.htaccess, .keep, etc.) must be included in the package
|
2014-09-24 17:04:37 +04:00
|
|
|
dot: true,
|
|
|
|
// Content of the cache directory is readable only for webserver. Thus
|
|
|
|
// we must to set "strict" option to false to prevent "EACCES" errors.
|
|
|
|
// At the same we need to see all errors that take place.
|
|
|
|
strict: false,
|
2017-11-10 18:17:12 +03:00
|
|
|
silent: false,
|
2017-11-12 03:59:09 +03:00
|
|
|
// Preserve root directory name (i.e. 'mibew/')
|
2017-11-10 18:17:12 +03:00
|
|
|
base: '.'
|
2014-09-24 17:04:37 +04:00
|
|
|
}
|
2014-08-13 13:04:44 +04:00
|
|
|
var version = config.package.version;
|
2014-08-07 15:04:45 +04:00
|
|
|
|
|
|
|
return eventStream.merge(
|
2014-09-24 17:04:37 +04:00
|
|
|
gulp.src(sources, srcOptions)
|
2014-08-07 15:04:45 +04:00
|
|
|
.pipe(zip('mibew-' + version + '.zip')),
|
2014-09-24 17:04:37 +04:00
|
|
|
gulp.src(sources, srcOptions)
|
2014-08-07 15:04:45 +04:00
|
|
|
.pipe(tar('mibew-' + version + '.tar'))
|
|
|
|
.pipe(gzip())
|
|
|
|
)
|
2017-02-08 10:41:18 +03:00
|
|
|
.pipe(chmod(644))
|
2017-11-11 02:44:40 +03:00
|
|
|
.pipe(gulp.dest(config.releasePath));
|
2021-01-29 19:54:44 +03:00
|
|
|
}));
|
2017-11-11 02:44:40 +03:00
|
|
|
|
2017-11-12 03:59:09 +03:00
|
|
|
// Pack translations for release as .zip and .tar.gz archives
|
|
|
|
gulp.task('pack-i18n', function(callback) {
|
|
|
|
return getChildDirs(config.i18nPath + '/translations')
|
|
|
|
.then(function (dirs) {
|
|
|
|
return Promise.all(dirs.map(function (dir) {
|
|
|
|
return new Promise(function(resolve, reject) {
|
2017-11-11 02:44:40 +03:00
|
|
|
|
2017-11-12 03:59:09 +03:00
|
|
|
var srcOptions = {
|
|
|
|
base: config.releasePath
|
|
|
|
};
|
|
|
|
|
|
|
|
eventStream.merge(
|
|
|
|
gulp.src(config.releasePath + '/' + dir
|
|
|
|
+ '/**/*', srcOptions)
|
|
|
|
.pipe(zip(config.i18nPrefix + dir
|
|
|
|
+ config.i18nSuffix + '.zip')),
|
|
|
|
gulp.src(config.releasePath + '/' + dir
|
|
|
|
+ '/**/*', srcOptions)
|
|
|
|
.pipe(tar(config.i18nPrefix + dir
|
|
|
|
+ config.i18nSuffix + '.tar'))
|
|
|
|
.pipe(gzip())
|
|
|
|
)
|
|
|
|
.pipe(chmod(644))
|
|
|
|
.pipe(gulp.dest(config.releasePath))
|
|
|
|
.on('error', reject)
|
|
|
|
.on('end', resolve);
|
|
|
|
|
|
|
|
});
|
|
|
|
}));
|
|
|
|
});
|
2014-08-07 15:04:45 +04:00
|
|
|
});
|
|
|
|
|
2017-11-12 03:59:09 +03:00
|
|
|
// Tasks of releasing //////////////////
|
|
|
|
|
|
|
|
// Prepare release of Mibew Messenger
|
2014-08-28 12:38:07 +04:00
|
|
|
gulp.task('prepare-release', function(callback) {
|
2014-08-07 15:04:45 +04:00
|
|
|
runSequence(
|
2015-03-31 13:54:34 +03:00
|
|
|
'clean',
|
2017-11-12 03:59:09 +03:00
|
|
|
['phpcs', 'js', 'chat-styles', 'page-styles', 'generate-pot',
|
|
|
|
'generate-tmp-po'],
|
2014-08-07 15:04:45 +04:00
|
|
|
'pack-sources',
|
2017-11-12 03:59:09 +03:00
|
|
|
'post-pack-cleanup',
|
2014-08-07 15:04:45 +04:00
|
|
|
callback
|
|
|
|
);
|
2014-08-04 17:53:18 +04:00
|
|
|
});
|
|
|
|
|
2017-11-12 03:59:09 +03:00
|
|
|
// Prepare releases of translations for Mibew Messenger
|
|
|
|
gulp.task('prepare-i18n-release', function(callback) {
|
|
|
|
runSequence( 'clean-tmp-po',
|
|
|
|
'generate-pos',
|
|
|
|
'pack-i18n',
|
|
|
|
'clean-tmp-i18n-files',
|
|
|
|
callback
|
2017-11-12 02:20:45 +03:00
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2017-11-12 03:59:09 +03:00
|
|
|
// Mirror prepared releases of Mibew Messenger and its translations in a form
|
|
|
|
// intended for uploading into the CDN
|
|
|
|
gulp.task('prepare-for-upload', function(callback) {
|
|
|
|
gulp.src(config.releasePath + '/mibew-' + config.package.version + '.*')
|
|
|
|
.pipe(gulp.dest(config.uploadPath + '/core/' + config.package.version + '/'));
|
|
|
|
|
|
|
|
gulp.src(config.releasePath + '/mibew-i18n-translation-' + config.package.version + '-*.pot')
|
|
|
|
.pipe(gulp.dest(config.uploadPath + '/i18n/_pot/' + config.package.version + '/'));
|
|
|
|
|
|
|
|
return getChildDirs(config.i18nPath + '/translations')
|
|
|
|
.then(function (dirs) {
|
|
|
|
return Promise.all(dirs.map(function (dir) {
|
|
|
|
return new Promise(function(resolve, reject) {
|
|
|
|
gulp.src(config.releasePath + '/mibew-i18n-' + dir + '-' + config.package.version + '-*.*')
|
|
|
|
.pipe(gulp.dest(config.uploadPath + '/i18n/' + dir + '/' + config.package.version + '/'))
|
|
|
|
.on('error', reject)
|
|
|
|
.on('end', resolve);
|
|
|
|
});
|
|
|
|
}));
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
// Perform all preparations before uploading the release of Mibew Messenger and
|
|
|
|
// its translations into the CDN
|
|
|
|
gulp.task('prepare-all', function(callback) {
|
|
|
|
runSequence('clean-all', 'prepare-release', 'prepare-i18n-release',
|
|
|
|
'prepare-for-upload', callback);
|
2015-04-17 17:18:59 +03:00
|
|
|
});
|
|
|
|
|
2017-11-12 03:59:09 +03:00
|
|
|
// Prepare release archives of the development version of Mibew Messenger
|
2014-08-28 12:38:07 +04:00
|
|
|
gulp.task('default', function(callback) {
|
|
|
|
runSequence(
|
2015-04-17 16:07:25 +03:00
|
|
|
'clean',
|
2021-01-29 19:54:44 +03:00
|
|
|
['js', 'chat-styles', 'page-styles', 'generate-tmp-po'],
|
2014-08-28 12:38:07 +04:00
|
|
|
'pack-sources',
|
2021-01-29 19:54:44 +03:00
|
|
|
['post-pack-cleanup', 'clean-tmp-po'],
|
2014-08-28 12:38:07 +04:00
|
|
|
callback
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
2014-08-04 17:53:18 +04:00
|
|
|
/**
|
|
|
|
* Loads and prepare js file for a client side application with the specified
|
|
|
|
* name.
|
|
|
|
*
|
2017-11-12 03:59:09 +03:00
|
|
|
* @param {String} name Application name.
|
2014-08-04 17:53:18 +04:00
|
|
|
* @returns A files stream that can be piped to any gulp plugin.
|
|
|
|
*/
|
|
|
|
var getClientSideApp = function(name) {
|
|
|
|
var appSource = config.jsPath + '/source/' + name;
|
|
|
|
|
|
|
|
return gulp.src(appSource + '/**/*.js')
|
|
|
|
.pipe(order(
|
|
|
|
[
|
|
|
|
appSource + '/init.js',
|
|
|
|
// The following line is equivalent to
|
|
|
|
// gulp.src([appSource + '/*.js', '!' + appSource + '/app.js']);
|
|
|
|
appSource + '/!(app).js',
|
|
|
|
appSource + '/models/**/base*.js',
|
|
|
|
appSource + '/models/**/*.js',
|
|
|
|
appSource + '/collections/**/base*.js',
|
|
|
|
appSource + '/collections/**/*.js',
|
|
|
|
appSource + '/model_views/**/base*.js',
|
|
|
|
appSource + '/model_views/**/*.js',
|
|
|
|
appSource + '/collection_views/**/base*.js',
|
|
|
|
appSource + '/collection_views/**/*.js',
|
|
|
|
appSource + '/regions/**/base*.js',
|
|
|
|
appSource + '/regions/**/*.js',
|
|
|
|
appSource + '/layouts/**/base*.js',
|
|
|
|
appSource + '/layouts/**/*.js',
|
|
|
|
appSource + '/**/base*.js',
|
|
|
|
// The following line is equivalent to
|
|
|
|
// gulp.src([appSource + '/**/*.js', '!' + appSource + '/app.js']);
|
|
|
|
'!' + appSource + '/app.js',
|
|
|
|
appSource + '/app.js'
|
|
|
|
],
|
|
|
|
{base: process.cwd()}
|
|
|
|
))
|
|
|
|
.pipe(concat(name + '_app.js'));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Wraps a handlebars template with a function and attach it to the
|
|
|
|
* Handlebars.templates object.
|
|
|
|
*
|
|
|
|
* @returns {Function} A function that can be used in pipe() method of a file
|
|
|
|
* stream right after gulp-handlebars plugin.
|
|
|
|
*/
|
|
|
|
var wrapHandlebarsTemplate = function() {
|
|
|
|
return defineModule('plain', {
|
|
|
|
wrapper: '(function() {\n'
|
|
|
|
+ 'var templates = Handlebars.templates = Handlebars.templates || {};\n'
|
|
|
|
+ 'Handlebars.templates["<%= relative %>"] = <%= handlebars %>;\n'
|
|
|
|
+ '})()',
|
|
|
|
context: function(context) {
|
2015-01-23 14:34:24 +03:00
|
|
|
return {relative: context.file.relative.replace(/\.js$/, '').replace(/\\/g, '/')};
|
2014-08-04 17:53:18 +04:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2014-08-13 16:14:35 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Extracts gettext messages from handlebars templates.
|
|
|
|
*
|
|
|
|
* @returns {Function} A function that can be used in pipe() method of a file
|
|
|
|
* stream.
|
|
|
|
*/
|
|
|
|
var xgettextHandlebars = function() {
|
|
|
|
var helperRegExp = /\{{2}l10n\s*('|")(.*?[^\\])\1.*?\}{2}/g;
|
|
|
|
|
|
|
|
return through.obj(function (file, enc, callback) {
|
|
|
|
var po = new PoFile();
|
|
|
|
match = false,
|
|
|
|
contents = file.contents.toString();
|
|
|
|
|
|
|
|
while (match = helperRegExp.exec(contents)) {
|
2017-11-12 03:59:09 +03:00
|
|
|
// Try to find item in the .po file by its name
|
2014-08-13 16:14:35 +04:00
|
|
|
var item = lodash.find(po.items, function(item) {
|
|
|
|
return match[2] === item.msgid;
|
|
|
|
});
|
|
|
|
|
|
|
|
var line = contents.substr(0, match.index).split(/\r?\n|\r/g).length;
|
|
|
|
|
|
|
|
if (!item) {
|
2017-11-12 03:59:09 +03:00
|
|
|
// There is no such item, create new one
|
2014-08-13 16:14:35 +04:00
|
|
|
item = new PoFile.Item();
|
|
|
|
item.msgid = match[2].replace(/\\'/g, "'").replace(/\\"/g, '"');
|
|
|
|
po.items.push(item);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add new reference
|
|
|
|
item.references.push(file.relative + ':' + line);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update file contents
|
2021-01-29 19:54:44 +03:00
|
|
|
file.contents = Buffer.from(po.toString());
|
2014-08-13 16:14:35 +04:00
|
|
|
this.push(file);
|
|
|
|
|
|
|
|
callback();
|
|
|
|
});
|
|
|
|
}
|
2017-03-13 14:29:16 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieves list of all dirs which are placed in the specified one.
|
|
|
|
*
|
2017-11-11 02:44:40 +03:00
|
|
|
* @param {String} srcDir A dir to search.
|
2017-03-16 23:46:01 +03:00
|
|
|
* @returns Promise A promise which will be resolved with list of child dirs or
|
|
|
|
* rejected with the occured error.
|
2017-03-13 14:29:16 +03:00
|
|
|
*/
|
|
|
|
var getChildDirs = function(srcDir) {
|
2017-03-16 23:46:01 +03:00
|
|
|
return (new Promise(function(resolve, reject) {
|
|
|
|
fs.readdir(srcDir, function (err, files) {
|
|
|
|
if (err) {
|
|
|
|
reject(err);
|
|
|
|
} else {
|
|
|
|
resolve(files);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
})).then(function (files) {
|
2017-11-11 02:44:40 +03:00
|
|
|
// Replace all files that are not a directory with nulls.
|
2017-03-16 23:46:01 +03:00
|
|
|
return Promise.all(files.map(function (file) {
|
|
|
|
return new Promise(function (resolve, reject) {
|
2017-11-10 18:15:59 +03:00
|
|
|
fs.lstat(srcDir + '/' + file, function (err, stat) {
|
2017-03-16 23:46:01 +03:00
|
|
|
if (err) {
|
|
|
|
reject(err);
|
|
|
|
} else {
|
|
|
|
resolve(stat.isDirectory() ? file : null);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}));
|
|
|
|
}).then(function(dirs) {
|
2017-11-11 02:44:40 +03:00
|
|
|
// Remove all nulls from the array.
|
2017-03-16 23:46:01 +03:00
|
|
|
return dirs.filter(function (dir) {
|
|
|
|
return null !== dir;
|
|
|
|
});
|
2017-03-13 14:29:16 +03:00
|
|
|
});
|
|
|
|
}
|