//Main build script for Dojo var buildTimerStart = (new Date()).getTime(); load("jslib/logger.js"); load("jslib/fileUtil.js"); load("jslib/buildUtil.js"); load("jslib/buildUtilXd.js"); load("jslib/i18nUtil.js"); //NOTE: See buildUtil.DojoBuildOptions for the list of build options. //***************************************************************************** //Convert arguments to keyword arguments. var kwArgs = buildUtil.makeBuildOptions(arguments); //Set logging level. logger.level = kwArgs["log"]; //Execute the requested build actions var action = kwArgs.action; for(var i = 0; i < action.length; i ++){ logger.logPrefix = action[i] + ": "; this[action[i]](); logger.logPrefix = ""; } var buildTime = ((new Date().getTime() - buildTimerStart) / 1000); logger.info("Build time: " + buildTime + " seconds"); //***************************************************************************** //********* Start help ************ function help(){ var buildOptionText = ""; for(var param in buildUtil.DojoBuildOptions){ buildOptionText += param + "=" + buildUtil.DojoBuildOptions[param].defaultValue + "\n" + buildUtil.DojoBuildOptions[param].helpText + "\n\n"; } var helpText = "To run the build, you must have Java 1.4.2 or later installed.\n" + "To run a build run the following command from this directory:\n\n" + "> java -classpath ../shrinksafe/js.jar:../shrinksafe/shrinksafe.jar " + "org.mozilla.javascript.tools.shell.Main build.js [name=value...]\n\n" + "Here is an example of a typical release build:\n\n" + "> java -classpath ../shrinksafe/js.jar:../shrinksafe/shrinksafe.jar " + "org.mozilla.javascript.tools.shell.Main build.js profile=base action=release\n\n" + "If you get a 'java.lang.OutOfMemoryError: Java heap space' error, try increasing the " + "memory Java can use for the command:\n\n" + "> java -Xms256m -Xmx256m -classpath ../shrinksafe/js.jar:../shrinksafe/shrinksafe.jar " + "org.mozilla.javascript.tools.shell.Main build.js profile=base action=release\n\n" + "Change the 256 number to the number of megabytes you want to give Java.\n\n" + "The possible name=value build options are shown below with the defaults as their values:\n\n" + buildOptionText; print(helpText); } //********* End help ********* //********* Start clean ************ function clean(){ logger.info("Deleting: " + kwArgs.releaseDir); fileUtil.deleteFile(kwArgs.releaseDir); } //********* End clean ********* //********* Start release ********* function release(){ logger.info("Using profile: " + kwArgs.profileFile); logger.info("Using version number: " + kwArgs.version + " for the release."); if(!kwArgs.buildLayers){ clean(); } var dependencies = kwArgs.profileProperties.dependencies; var prefixes = dependencies.prefixes; var lineSeparator = fileUtil.getLineSeparator(); var copyrightText = fileUtil.readFile("copyright.txt"); var buildNoticeText = fileUtil.readFile("build_notice.txt"); //Find the dojo prefix path. Need it to process other module prefixes. var dojoPrefixPath = buildUtil.getDojoPrefixPath(prefixes); //Convert targeted build layers to an array. var buildLayers = null; if(kwArgs.buildLayers){ //Make sure to copy over any "source" files for the layers be targeted by //buildLayers. Otherwise dependencies will not be calculated correctly. buildLayers = kwArgs.buildLayers.split(","); } //Get the list of module directories we need to process. //They will be in the dependencies.prefixes array. //Copy each prefix dir to the releases and //operate on that copy instead of modifying the source. for(var i = 0; i < prefixes.length; i++){ var prefixName = prefixes[i][0]; var prefixPath = prefixes[i][1]; var finalPrefixPath = prefixPath; if(finalPrefixPath.indexOf(".") == 0 && prefixName != "dojo"){ finalPrefixPath = dojoPrefixPath + "/" + prefixPath; } _copyToRelease(prefixName, finalPrefixPath, kwArgs, buildLayers); if(kwArgs.symbol){ var releasePath = kwArgs.releaseDir + "/" + prefixName.replace(/\./g, "/"); buildUtil.insertSymbols(releasePath, kwArgs); } } //Fix all the prefix paths to be in the release directory. //Do this after the copy step above. If it is done as part //of that loop, then dojo path gets set first usually, and any prefixes //after it are wrong. for(var i = 0; i < prefixes.length; i++){ prefixes[i][1] = kwArgs.releaseDir + "/" + prefixes[i][0].replace(/\./g, "/"); } //Make sure dojo is clear before trying to map dependencies. if(typeof dojo != "undefined"){ dojo = undefined; } logger.trace("Building dojo.js and layer files"); var result = buildUtil.makeDojoJs(buildUtil.loadDependencyList(kwArgs.profileProperties, kwArgs), kwArgs.version, kwArgs); //Save the build layers. The first layer is dojo.js. var defaultLegalText = copyrightText + buildNoticeText; var dojoReleaseDir = kwArgs.releaseDir + "/dojo/"; var layerIgnoreString = ""; var nlsIgnoreString = ""; //Add an ending comma to the list to make matches easier. //Also make sure we normalize to unix path separators. if(kwArgs.buildLayers){ kwArgs.buildLayers += ","; kwArgs.buildLayers = kwArgs.buildLayers.replace(/\\/g, "/"); } for(var i = 0; i < result.length; i++){ var currentLayer = result[i]; var layerName = currentLayer.layerName; var layerLegalText = (currentLayer.copyrightFile ? fileUtil.readFile(currentLayer.copyrightFile) : defaultLegalText); var fileName = dojoReleaseDir + currentLayer.layerName; var fileContents = currentLayer.contents; //Build up string of files to ignore for the directory optimization step var ignoreName = layerName.replace(/\.\.\//g, ""); var nameSegment = ignoreName.replace(/\.js$/, ""); layerIgnoreString += (layerIgnoreString ? "|" : "") + buildUtil.regExpEscape(ignoreName) + "$"; layerIgnoreString += "|" + buildUtil.regExpEscape(ignoreName + ".uncompressed.js") + "$"; if(nameSegment.indexOf("/") != -1){ nameSegment = nameSegment.substring(nameSegment.lastIndexOf("/") + 1, nameSegment.length); } nlsIgnoreString += (nlsIgnoreString ? "|" : "") + buildUtil.regExpEscape(nameSegment); //If only want to build certain layers, skip ones that do not match. if(kwArgs.buildLayers && kwArgs.buildLayers.indexOf(layerName + ",") == -1){ continue; } //Burn in djConfig for dojo.js/xd.js if requested. if(kwArgs.scopeDjConfig && (layerName.match(/dojo\.xd\.js$/) || layerName.match(/dojo\.js$/))){ fileContents = buildUtil.setScopeDjConfig(fileContents, kwArgs.scopeDjConfig); } //Burn in scope names for dojo.js/xd.js if requested. if(kwArgs.scopeMap && (layerName.match(/dojo\.xd\.js$/) || layerName.match(/dojo\.js$/))){ fileContents = buildUtil.setScopeNames(fileContents, kwArgs.scopeMap); } //Burn in xd path for dojo if requested, and only do this in dojo.xd.js. if(layerName.match(/dojo\.xd\.js/) && kwArgs.xdDojoPath){ fileContents = buildUtilXd.setXdDojoConfig(fileContents, kwArgs.xdDojoPath); } //Flatten resources fileContents = i18nUtil.flattenLayerFileBundles(fileName, fileContents, kwArgs); //Remove console statements if desired fileContents = buildUtil.stripConsole(fileContents, kwArgs.stripConsole); //Save uncompressed file. var uncompressedFileName = fileName + ".uncompressed.js"; var uncompressedContents = layerLegalText + fileContents; if(layerName.match(/\.xd\.js$/) && !layerName.match(/dojo(\.xd)?\.js/)){ uncompressedContents = buildUtilXd.makeXdContents(uncompressedContents, prefixes, kwArgs); } fileUtil.saveUtf8File(uncompressedFileName, uncompressedContents); //Intern strings if desired. Do this before compression, since, in the xd case, //"dojo" gets converted to a shortened name. if(kwArgs.internStrings){ logger.info("Interning strings for file: " + fileName); var prefixes = dependencies["prefixes"] || []; var skiplist = dependencies["internSkipList"] || []; buildUtil.internTemplateStringsInFile(uncompressedFileName, dojoReleaseDir, prefixes, skiplist); //Load the file contents after string interning, to pick up interned strings. fileContents = fileUtil.readFile(uncompressedFileName); }else{ fileContents = uncompressedContents; } //Save compressed file. logger.trace("Optimizing (" + kwArgs.layerOptimize + ") file: " + fileName); var compressedContents = buildUtil.optimizeJs(fileName, fileContents, layerLegalText, kwArgs.layerOptimize); fileUtil.saveUtf8File(fileName, compressedContents); } //Save the dependency lists to build.txt var buildText = "Files baked into this build:" + lineSeparator; for(var i = 0; i < result.length; i++){ buildText += lineSeparator + result[i].layerName + ":" + lineSeparator; buildText += result[i].depList.join(lineSeparator) + lineSeparator; } fileUtil.saveFile(kwArgs.releaseDir + "/dojo/build.txt", buildText); logger.info(buildText); //Run string interning, xd file building, etc.. on the prefix dirs in the //release area. var layerIgnoreRegExp = new RegExp("(" + layerIgnoreString + ")"); var nlsIgnoreRegExp = new RegExp("\\/nls\\/(" + nlsIgnoreString + ")_"); for(var i = 0; i < prefixes.length; i++){ var copyrightText = null; if(prefixes[i][2]){ copyrightText = fileUtil.readFile(prefixes[i][2]); } //Optimize the release dirs, but only if we are not building just a layer. if(!kwArgs.buildLayers){ _optimizeReleaseDirs(prefixes[i][0], prefixes[i][1], copyrightText, kwArgs, layerIgnoreRegExp, nlsIgnoreRegExp); } } //Copy over DOH if tests where copied. if(kwArgs.copyTests && !kwArgs.mini){ fileUtil.copyDir("../doh", kwArgs.releaseDir + "/util/doh", /./); } //Remove any files no longer needed. if(kwArgs.mini && kwArgs.internStrings){ fileUtil.deleteFile(kwArgs.releaseDir + "/dijit/templates"); fileUtil.deleteFile(kwArgs.releaseDir + "/dijit/form/templates"); fileUtil.deleteFile(kwArgs.releaseDir + "/dijit/layout/templates"); } logger.info("Build is in directory: " + kwArgs.releaseDir); } //********* End release ********* //********* Start _copyToRelease ********* function _copyToRelease(/*String*/prefixName, /*String*/prefixPath, /*Object*/kwArgs, /*Array?*/buildLayers){ //summary: copies modules and supporting files from the prefix path to the release //directory. Also adds code guards to module resources. var prefixSlashName = prefixName.replace(/\./g, "/"); var releasePath = kwArgs.releaseDir + "/" + prefixSlashName; var copyRegExps = { include: /./ }; //Use the copyRegExps to filter out tests if requested. if(!kwArgs.copyTests){ copyRegExps.exclude = /\/tests\//; } if(kwArgs.mini){ copyRegExps.exclude = /\/tests\/|\/demos\/|tests\.js|dijit\/bench|dijit\/themes\/noir|dijit\/themes\/themeTest|dijit\/themes\/templateThemeTest/; } logger.info("Copying: " + prefixPath + " to: " + releasePath); var copiedFiles = fileUtil.copyDir(prefixPath, releasePath, copyRegExps, true); //If want a different selector engine, adjust that now. //Copy the new selector js over the dojo._base.query file if(prefixName == "dojo" && kwArgs.query == "sizzle"){ fileUtil.copyFile(releasePath + "/_base/query-sizzle.js", releasePath + "/_base/query.js"); } //Make sure to copy over any "source" files for the layers be targeted by //buildLayers. Otherwise dependencies will not be calculated correctly. if(buildLayers){ for(i = 0; i < buildLayers.length; i++){ var relativeLayerPath = buildLayers[i].replace(/\.\.\//g, ""); //See if relativeLayerPath has teh prefix slash name in it. //This means the layer is probably in this prefix dir (but no guarantee) //This is a bit hacky. if(relativeLayerPath.indexOf(prefixSlashName) == 0){ //Remove the prefix part from the dir and add the prefix path to get a //full path. var layerPathSuffix = relativeLayerPath.replace(prefixSlashName, ""); relativeLayerPath = prefixPath + layerPathSuffix; //If that source path exists, it means we need to copy over the source //layer file. if((new java.io.File(relativeLayerPath)).exists()){ //Need to copy over from the source area. var destPath = releasePath + layerPathSuffix; fileUtil.copyFile(relativeLayerPath, destPath); } } } } //Put in code guards for each resource, to protect against redefinition of //code in the layered build cases. Also inject base require calls if there is //a layer with the customBase attribute. Do this here before the layers are built. if(copiedFiles){ var needBaseRequires = false; var layers = kwArgs.profileProperties.dependencies.layers; if(layers){ for(var i = 0; i < layers.length; i++){ if((needBaseRequires = layers[i].customBase)){ break; } } } buildUtil.addGuardsAndBaseRequires(copiedFiles, needBaseRequires); } } //********* End _copyToRelease ********* //********* Start _optimizeReleaseDirs ********* function _optimizeReleaseDirs( /*String*/prefixName, /*String*/prefixPath, /*String*/copyrightText, /*Object*/kwArgs, /*RegExp*/layerIgnoreRegExp, /*RegExp*/nlsIgnoreRegExp){ //summary: runs intern strings, i18n bundle flattening and xdomain file generation //on the files in a release directory, if those options are enabled. var releasePath = kwArgs.releaseDir + "/" + prefixName.replace(/\./g, "/"); var prefixes = kwArgs.profileProperties.dependencies.prefixes; //Intern strings if desired. if(kwArgs.internStrings){ logger.info("Interning strings for: " + releasePath); buildUtil.internTemplateStrings(kwArgs.profileProperties.dependencies, releasePath, layerIgnoreRegExp); } //Process build conditionals in non-layer module files. buildUtil.processConditionalsForDir(releasePath, layerIgnoreRegExp, kwArgs); //Flatten bundles inside the directory i18nUtil.flattenDirBundles(prefixName, prefixPath, kwArgs, nlsIgnoreRegExp); if(kwArgs.loader == "xdomain"){ buildUtilXd.xdgen(prefixName, prefixPath, prefixes, layerIgnoreRegExp, kwArgs); } buildUtil.optimizeJsDir(releasePath, layerIgnoreRegExp, copyrightText, kwArgs.optimize, kwArgs.stripConsole); if(kwArgs.cssOptimize){ buildUtil.optimizeCss(releasePath, kwArgs.cssOptimize, kwArgs.cssImportIgnore); } } //********* End _optimizeReleaseDirs *********