diff --git a/build/post-app.js b/build/post-app.js index 3a35ac6ed71c..cda0d314fa5d 100644 --- a/build/post-app.js +++ b/build/post-app.js @@ -25,7 +25,12 @@ exports.execute = function(options, webapp) { require('./webapp-optimize').execute(options); if (options.DEBUG === '0') { - // Generate $(PROFILE_FOLDER)/webapps/APP/application.zip - require('./webapp-zip').execute(options); + // Workaround for bug 955999, after multilocale, settings and system + // generate too long args exceed nsIProcess.runw() can handle. + // Thus, we clean webapp.asts values which generates from l10n in order to + // pass into nsIProcess.runw() + // It can remove by bug 1131516 once all post-app tasks are refactored. + options.webapp.asts = ''; + nodeHelper.require('webapp-zip', options); } }; diff --git a/build/test/unit/webapp_zip_test.js b/build/test/unit/webapp_zip_test.js index 24b509e94396..9ebac44a6f2c 100644 --- a/build/test/unit/webapp_zip_test.js +++ b/build/test/unit/webapp_zip_test.js @@ -3,6 +3,7 @@ var assert = require('chai').assert; var proxyquire = require('proxyquire'); var mockUtils = require('./mock_utils.js'); +var fsPath = require('path'); suite('webapp-zip.js', function() { var app; @@ -17,18 +18,18 @@ suite('webapp-zip.js', function() { setup(function() { app = proxyquire.noCallThru().load( - '../../webapp-zip', { - './utils': mockUtils - }); - var GetFile = function(path) { - this.path = path; + '../../webapp-zip', { + './utils': mockUtils + }); + var GetFile = function(filePath) { + this.path = filePath; this.append = function(subPath) { this.path += ('/' + subPath); }; this.clone = function() { return new GetFile(this.path); }; - this.leafName = this.path; + this.leafName = fsPath.basename(this.path); this.parent = this; this.exists = function() { return fileExists; @@ -43,18 +44,15 @@ suite('webapp-zip.js', function() { return isDirectory; }; }; - mockUtils.getFile = function(path) { - filePath = path; - return new GetFile(path); + mockUtils.getFile = function() { + var args = Array.prototype.slice.call(arguments); + filePath = fsPath.join.apply(fsPath, args); + return new GetFile(filePath); }; - mockUtils.createZip = function() { - return { - open: function(file, mode) { - zipFilePath = file.path; - zipMode = mode; - } - }; + mockUtils.createZip = function(zipPath) { + zipFilePath = zipPath; + return {}; }; mockUtils.getCompression = function(type) { @@ -96,24 +94,24 @@ suite('webapp-zip.js', function() { test('setOptions', function() { webappZip.setOptions(mockOptions); assert.equal(zipFilePath, 'testTargetDir/testDomain/application.zip'); - assert.equal(zipMode, 0x04 | 0x08 | 0x20); }); test('getCompression', function() { var pathInZip = 'pathInZip'; - webappZip.webapp = { - metaData: { - external: false, - zip: { + webappZip.options = { + webapp: { + metaData: { + external: false, + zip: {} } } }; - webappZip.webapp.metaData.zip.mmap_files = [pathInZip]; + webappZip.options.webapp.metaData.zip.mmap_files = [pathInZip]; assert.equal(webappZip.getCompression(pathInZip), 'none'); // we don't compress jpg file. pathInZip = 'pathInZip.jpg'; - delete webappZip.webapp.metaData; + delete webappZip.options.webapp.metaData; assert.equal(webappZip.getCompression(pathInZip), 'none'); pathInZip = 'pathInZip.png'; @@ -124,23 +122,23 @@ suite('webapp-zip.js', function() { var file = mockUtils.getFile('locales'); isFile = true; fileExists = true; - webappZip.config = { - GAIA_CONCAT_LOCALES: '1' - }; - webappZip.webapp = { - sourceDirectoryName: 'testSourceDirectory' + webappZip.options = { + GAIA_CONCAT_LOCALES: '1', + webapp: { + sourceDirectoryName: 'testSourceDirectory' + } }; - webappZip.buildDir = mockUtils.getFile('test'); + webappZip.options.webapp.buildDirectoryFilePath = 'test'; assert.equal(webappZip.isExcludedFromZip(file), true, 'Ignore l10n files if they have been inlined or concatenated'); file = mockUtils.getFile('locales-obj'); - webappZip.config.GAIA_CONCAT_LOCALES = '0'; + webappZip.options.GAIA_CONCAT_LOCALES = '0'; assert.equal(webappZip.isExcludedFromZip(file), true, 'Ignore l10n files if they have been inlined or concatenated'); file = mockUtils.getFile('testapppath/test'); - webappZip.buildDir = mockUtils.getFile('testapppath'); + webappZip.options.webapp.buildDirectoryFilePath = 'testapppath'; assert.equal(webappZip.isExcludedFromZip(file), true, 'Ignore test file'); file = mockUtils.getFile('testapppath/.git'); @@ -166,22 +164,24 @@ suite('webapp-zip.js', function() { var webappZip; var isExcludedFromZip; var testResult; + setup(function() { fileExists = true; isExcludedFromZip = false; - mockUtils.addEntryContentWithTime = function(zip, pathInZip, l10nFile, - time, needCompression) { + mockUtils.addFileToZip = function(zip, pathInZip, file, compression) { testResult = { zip: zip, pathInZip: pathInZip, - l10nFile: l10nFile, - needCompression: needCompression + file: file, + compression: compression }; }; webappZip = new app.WebappZip(); - webappZip.buildDir = mockUtils.getFile('testBuildDir'); - webappZip.getImagePathByResolution = function(file, pathInZip) { - return pathInZip + '_bestResolution'; + webappZip.options = { + GAIA_DEFAULT_LOCALE: 'en-US-test', + webapp: { + buildDirectoryFilePath: 'testBuildDir' + } }; webappZip.isExcludedFromZip = function() { return isExcludedFromZip; @@ -189,19 +189,12 @@ suite('webapp-zip.js', function() { webappZip.getCompression = function() { return '1'; }; - webappZip.config = { - GAIA_DEFAULT_LOCALE: 'en-US-test' - }; - webappZip.zipFile = { - hasEntry: function(pathInZip) { - return false; - }, - }; }); teardown(function() { testResult = null; }); + test('file is hiddenr or is set excluded from zip', function() { var testFile = mockUtils.getFile('testfile'); isHidden = true; @@ -216,14 +209,12 @@ suite('webapp-zip.js', function() { test('add localize html file', function() { var testFile = mockUtils.getFile('testBuildDir/testFile.html'); - // testFile_bestResolution isFile = true; fileExists = true; webappZip.addToZip(testFile); assert.equal(testResult.pathInZip, 'testFile.html'); - assert.equal(testResult.l10nFile.path, - 'testBuildDir/testFile.html/testBuildDir/testFile.html.en-US-test'); - + assert.equal(testResult.file.path, + 'testBuildDir/testFile.html.en-US-test'); }); }); }); diff --git a/build/utils-node.js b/build/utils-node.js index 99761d38dfdc..80379f45ac09 100644 --- a/build/utils-node.js +++ b/build/utils-node.js @@ -450,7 +450,7 @@ module.exports = { } }, - addFileToZip: function(zip, zipPath, pathInZip, file, compression) { + addFileToZip: function(zip, pathInZip, file, compression) { if (!file.exists()) { return; } @@ -460,8 +460,15 @@ module.exports = { }); }, + hasFileInZip: function(zip, pathInZip) { + return zip.file(pathInZip); + }, + closeZip: function(zip, zipPath) { - fs.writeFileSync(zipPath, zip.generate({ type: 'nodebuffer' })); + fs.writeFileSync(zipPath, zip.generate({ + type: 'nodebuffer', + platform: process.platform + })); }, getLocaleBasedir: function(src) { diff --git a/build/utils-xpc.js b/build/utils-xpc.js index 74944f07fe33..41503a6f9599 100644 --- a/build/utils-xpc.js +++ b/build/utils-xpc.js @@ -949,10 +949,9 @@ function Commander(cmd) { process.init(_file); process.runw(true, args, args.length); callback && callback(process.exitValue); - } catch (e) { + } catch (err) { callback && callback(1); - throw new Error('having trouble when execute ' + command + - ' ' + args.join(' ')); + throw err; } processEvents(function () { @@ -1097,10 +1096,9 @@ function getDocument(content) { * @param zip {nsIZipWriter} - the zip file * @param pathInZip {string} - the relative path to the new file * @param data {string} - the content of the file - * @param time {string} - the timestamp of the file * @param compression {number} - the enum shows above */ -function addEntryContentWithTime(zip, pathInZip, data, time, compression) { +function addFileToZip(zip, pathInZip, data, compression) { if (!data) { return; } @@ -1121,10 +1119,8 @@ function addEntryContentWithTime(zip, pathInZip, data, time, compression) { input.init(data, -1, -1, 0); } - zip.addEntryStream( - pathInZip, time || 0, compression, input, false); + zip.addEntryStream(pathInZip, Date.now() * 1000, compression, input, false); input.close(); - } /** @@ -1140,6 +1136,10 @@ function getCompression(type) { } } +function hasFileInZip(zip, pathInZip) { + return zip.hasEntry(pathInZip); +} + /** * Generate UUID. It's just a wrapper of 'nsIUUIDGenerator' * See the 'nsIUUIDGenerator' page on MDN. @@ -1176,23 +1176,23 @@ function copyRec(source, target) { /** * Create an empty ZIP file. - * For users, the way to read/write a ZIP file is - * - * 1. create an nsIZipWriter - * 2. open it with the open method, which - * 3. puts an nsIFile as the first argument - * - * For example: - * - * createZip().open(getFile(, )) * * @return {nsIZipWriter} */ -function createZip() { +function createZip(zipPath) { var zip = Cc['@mozilla.org/zipwriter;1'].createInstance(Ci.nsIZipWriter); + // PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE + zip.open(getFile(zipPath), 0x04 | 0x08 | 0x20); return zip; } +function closeZip(zip) { + if (zip.alignStoredFiles) { + zip.alignStoredFiles(4096); + } + zip.close(); +} + /** * Remove all listed files in the directory. * @@ -1250,7 +1250,7 @@ var scriptLoader = { * Run specific build task on Node.js if RUN_ON_NODE is on, otherwise we go back * to XPCShell. */ -function NodeHelper(path) { +function NodeHelper() { if (getEnv('RUN_ON_NODE') === '1') { var node = new Commander('node'); node.initPath(getEnvPath()); @@ -1260,7 +1260,7 @@ function NodeHelper(path) { }; } else { this.require = function(path, options) { - require(path).execute(options); + return require(path).execute(options); }; } } @@ -1296,6 +1296,8 @@ exports.getOsType = getOsType; exports.generateUUID = generateUUID; exports.copyRec = copyRec; exports.createZip = createZip; +exports.closeZip = closeZip; +exports.hasFileInZip = hasFileInZip; exports.scriptParser = Reflect.parse; exports.deleteFile = deleteFile; exports.listFiles = listFiles; @@ -1325,7 +1327,7 @@ exports.Services = Services; exports.concatenatedScripts = concatenatedScripts; exports.dirname = dirname; exports.basename = basename; -exports.addEntryContentWithTime = addEntryContentWithTime; +exports.addFileToZip = addFileToZip; exports.getCompression = getCompression; exports.existsInAppDirs = existsInAppDirs; exports.removeFiles = removeFiles; diff --git a/build/utils.js b/build/utils.js index d0879fbd8f36..41394096af25 100644 --- a/build/utils.js +++ b/build/utils.js @@ -318,6 +318,8 @@ exports.generateUUID = utils.generateUUID; exports.copyRec = utils.copyRec; exports.getAppStatus = getAppStatus; exports.createZip = utils.createZip; +exports.closeZip = utils.closeZip; +exports.hasFileInZip = utils.hasFileInZip; exports.scriptParser = utils.scriptParser; exports.scriptLoader = utils.scriptLoader; exports.FILE_TYPE_FILE = FILE_TYPE_FILE; @@ -353,7 +355,7 @@ exports.Services = utils.Services; exports.concatenatedScripts = utils.concatenatedScripts; exports.dirname = utils.dirname; exports.basename = utils.basename; -exports.addEntryContentWithTime = utils.addEntryContentWithTime; +exports.addFileToZip = utils.addFileToZip; exports.copyDirTo = utils.copyDirTo; exports.existsInAppDirs = utils.existsInAppDirs; exports.getCompression = utils.getCompression; diff --git a/build/webapp-zip.js b/build/webapp-zip.js index 73ccd0355c00..4ed6e667685a 100644 --- a/build/webapp-zip.js +++ b/build/webapp-zip.js @@ -1,37 +1,30 @@ +'use strict'; + /** - * Zip app from build_stage to profile. + * Generate $(PROFILE_FOLDER)/webapps/APP/application.zip from build_stage + * to profile. * Additionally, it will also filter images by resolution and some excluded * conditions, which should move to other task, bug 1010095. */ -/* global require, exports, dump */ -'use strict'; + var utils = require('./utils'); var WebappZip = function() { - this.config = null; - this.webapp = null; - this.buildDir = null; + this.options = null; this.zipFile = null; }; WebappZip.prototype.setOptions = function(options) { - this.config = options.config; - this.webapp = options.webapp; - this.buildDir = utils.getFile(this.webapp.buildDirectoryFilePath); + this.options = options; - var targetAppFolder = utils.getFile(this.webapp.profileDirectoryFilePath); + var targetAppFolder = utils.getFile(options.webapp.profileDirectoryFilePath); utils.ensureFolderExists(targetAppFolder); - - var zipContent = targetAppFolder.clone(); - zipContent.append('application.zip'); - // PR_CREATE_FILE | PR_CREATE_FILE | PR_TRUNCATE - var mode = 0x04 | 0x08 | 0x20; - this.zipFile = utils.createZip(); - this.zipFile.open(zipContent, mode); + this.zipPath = utils.joinPath(targetAppFolder.path, 'application.zip'); + this.zipFile = utils.createZip(this.zipPath); }; WebappZip.prototype.getCompression = function(pathInZip) { - var webapp = this.webapp; + var webapp = this.options.webapp; if (webapp.metaData && webapp.metaData.external === false && webapp.metaData.zip && webapp.metaData.zip.mmap_files && webapp.metaData.zip.mmap_files.indexOf(pathInZip) !== -1) { @@ -41,8 +34,8 @@ WebappZip.prototype.getCompression = function(pathInZip) { // benefit but costs cpu when reading from the zip. var ext = pathInZip.split('.').reverse()[0].toLowerCase(); return (['jpg', 'jpeg'].indexOf(ext) !== -1) ? - utils.getCompression('none') : - utils.getCompression('best'); + utils.getCompression('none') : + utils.getCompression('best'); } }; @@ -51,21 +44,20 @@ WebappZip.prototype.isExcludedFromZip = function(file) { if (!(file && file.exists() && file.isFile())) { return true; } - } catch (e) { - dump('isExcludedFromZip error, file.path: ' + file.path + '\n'); - throw(e); + } catch (err) { + utils.log('webapp-zip', 'isExcludedFromZip error with ' + file.path + '\n'); + throw(err); } - var self = this; + var options = this.options; var excludedFuncs = [ function fileExist(file) { return !file.exists(); }, function isLocales(file) { - return self.config.GAIA_CONCAT_LOCALES === '1' && + return options.GAIA_CONCAT_LOCALES === '1' && /locales[^-]/.test(file.path); }, function isSpecificProperties(file) { - var options = self.config; if(utils.getExtension(file.path) === 'properties' && file.path.indexOf('locales') !== -1 && options.GAIA_CONCAT_LOCALES === '0' && @@ -83,7 +75,7 @@ WebappZip.prototype.isExcludedFromZip = function(file) { return false; }, function isBuild(file) { - var appDirPath = self.webapp.sourceDirectoryName; + var appDirPath = options.webapp.sourceDirectoryName; return new RegExp(utils.joinPath(appDirPath, 'build') .replace(/\\/g, '\\\\') + '|build.txt') .test(file.path); @@ -101,23 +93,24 @@ WebappZip.prototype.isExcludedFromZip = function(file) { return file.isHidden(); }, function isTest(file) { - var appPath = self.buildDir; - var path = file.path.substr(appPath.path.length + 1).split(/[\\/]/)[0]; + var appPath = options.webapp.buildDirectoryFilePath; + var path = file.path.substr(appPath.length + 1).split(/[\\/]/)[0]; return path === 'test'; }, function isGit(file) { - var appPath = self.buildDir; - var path = file.path.substr(appPath.path.length + 1).split(/[\\/]/)[0]; + var appPath = options.webapp.buildDirectoryFilePath; + var path = file.path.substr(appPath.length + 1).split(/[\\/]/)[0]; return path === '.git'; }, function isL10n(file) { - return (self.config.GAIA_CONCAT_LOCALES === '1' && - (file.leafName === 'locales' || file.parent.leafName === 'locales')); + return (options.GAIA_CONCAT_LOCALES === '1' && + (file.leafName === 'locales' || + utils.getFile(file.path, '..').leafName === 'locales')); }, function isConcatenatedL10n(file) { return ((file.leafName === 'locales-obj' || - file.parent.leafName === 'locales-obj') && - self.config.GAIA_CONCAT_LOCALES !== '1'); + utils.getFile(file.path, '..').leafName === 'locales-obj') && + options.GAIA_CONCAT_LOCALES !== '1'); } ]; for (var index in excludedFuncs) { @@ -136,7 +129,7 @@ WebappZip.prototype.addToZip = function(file) { } var pathInZip = file.path.substr( - this.buildDir.path.length + 1); + this.options.webapp.buildDirectoryFilePath.length + 1); var compression = this.getCompression(pathInZip); pathInZip = pathInZip.replace(/\\/g, '/'); @@ -147,44 +140,31 @@ WebappZip.prototype.addToZip = function(file) { // nsIZipWriter should not receive any path starting with `/`, // it would put files in a folder with empty name... pathInZip = pathInZip.replace(/^\/+/, ''); + var zip = this.zipFile; // Regular file if (file.isFile()) { - try { - if (/\.html$/.test(file.leafName)) { - // this file might have been pre-translated for the default locale - var l10nFile = file.parent.clone(); - l10nFile.append(file.leafName + '.' + this.config.GAIA_DEFAULT_LOCALE); - if (l10nFile.exists()) { - utils.addEntryContentWithTime(this.zipFile, pathInZip, l10nFile, - 0, compression); - return; - } + if (/\.html$/.test(file.leafName)) { + // This file might have been pre-translated for the default locale + var l10nFile = utils.getFile(file.path + '.' + + this.options.GAIA_DEFAULT_LOCALE); + if (l10nFile.exists()) { + utils.addFileToZip(zip, pathInZip, l10nFile, compression); + return; } - - var re = new RegExp('\\.html\\.' + this.config.GAIA_DEFAULT_LOCALE); - if (!this.zipFile.hasEntry(pathInZip) && !re.test(file.leafName)) { - utils.addEntryContentWithTime(this.zipFile, pathInZip, file, - 0, compression); - } - } catch (e) { - throw new Error('Unable to add following file in zip: ' + - file.path + '\n' + e); } - } -}; -WebappZip.prototype.closeZip = function() { - if (this.zipFile.alignStoredFiles) { - this.zipFile.alignStoredFiles(4096); + var re = new RegExp('\\.html\\.' + this.options.GAIA_DEFAULT_LOCALE); + if (!utils.hasFileInZip(zip, pathInZip) && !re.test(file.leafName)) { + utils.addFileToZip(zip, pathInZip, file, compression); + } } - this.zipFile.close(); }; WebappZip.prototype.execute = function(options) { - // If config.BUILD_APP_NAME isn't `*`, we only accept one webapp - if (options.config.BUILD_APP_NAME != '*' && - options.webapp.sourceDirectoryName != options.config.BUILD_APP_NAME) { + // If BUILD_APP_NAME isn't `*`, we only accept one webapp + if (options.BUILD_APP_NAME != '*' && + options.webapp.sourceDirectoryName != options.BUILD_APP_NAME) { return; } @@ -196,23 +176,19 @@ WebappZip.prototype.execute = function(options) { this.setOptions(options); - var files = utils.ls(this.buildDir, true); - files.forEach(this.addToZip.bind(this)); + var buildDir = utils.getFile(options.webapp.buildDirectoryFilePath); + utils.ls(buildDir, true).forEach(this.addToZip.bind(this)); - this.closeZip(); + utils.closeZip(this.zipFile, this.zipPath); }; function execute(options) { - var webapp = options.webapp; var profileDir = utils.getFile(options.PROFILE_DIR); utils.ensureFolderExists(profileDir); - profileDir.append('webapps'); - utils.ensureFolderExists(profileDir); + var webappsDir = utils.getFile(options.PROFILE_DIR, 'webapps'); + utils.ensureFolderExists(webappsDir); - (new WebappZip()).execute({ - config: options, - webapp: webapp - }); + (new WebappZip()).execute(options); } exports.execute = execute;