12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277 |
- /*jslint node: true, latedef: nofunc*/
- 'use strict';
- var fs = require('fs');
- var path = require('path');
- var os = require('os');
- var child_process = require('child_process');
- var crypto = require('crypto');
- var zlib = require('zlib');
- var readline = require('readline');
- var request = require('request');
- var globby = require('globby');
- var jshint = require('gulp-jshint');
- var rimraf = require('rimraf');
- var stripComments = require('strip-comments');
- var mkdirp = require('mkdirp');
- var eventStream = require('event-stream');
- var gulp = require('gulp');
- var gulpInsert = require('gulp-insert');
- var gulpZip = require('gulp-zip');
- var gulpRename = require('gulp-rename');
- var gulpReplace = require('gulp-replace');
- var os = require('os');
- var Promise = require('bluebird');
- var requirejs = require('requirejs');
- var karma = require('karma').Server;
- var yargs = require('yargs');
- var aws = require('aws-sdk');
- var mime = require('mime');
- var compressible = require('compressible');
- var packageJson = require('./package.json');
- var version = packageJson.version;
- if (/\.0$/.test(version)) {
- version = version.substring(0, version.length - 2);
- }
- var karmaConfigFile = path.join(__dirname, 'Specs/karma.conf.js');
- var travisDeployUrl = "http://cesium-dev.s3-website-us-east-1.amazonaws.com/cesium/";
- //Gulp doesn't seem to have a way to get the currently running tasks for setting
- //per-task variables. We use the command line argument here to detect which task is being run.
- var taskName = process.argv[2];
- var noDevelopmentGallery = taskName === 'release' || taskName === 'makeZipFile';
- var buildingRelease = noDevelopmentGallery;
- var minifyShaders = taskName === 'minify' || taskName === 'minifyRelease' || taskName === 'release' || taskName === 'makeZipFile' || taskName === 'buildApps';
- //travis reports 32 cores but only has 3GB of memory, which causes the VM to run out. Limit to 8 cores instead.
- var concurrency = Math.min(os.cpus().length, 8);
- //Since combine and minify run in parallel already, split concurrency in half when building both.
- //This can go away when gulp 4 comes out because it allows for synchronous tasks.
- if (buildingRelease) {
- concurrency = concurrency / 2;
- }
- var sourceFiles = ['Source/**/*.js',
- '!Source/*.js',
- '!Source/Workers/**',
- '!Source/ThirdParty/Workers/**',
- 'Source/Workers/createTaskProcessorWorker.js'];
- var buildFiles = ['Specs/**/*.js',
- '!Specs/SpecList.js',
- 'Source/Shaders/**/*.glsl'];
- var jsHintFiles = ['Source/**/*.js',
- '!Source/Shaders/**',
- '!Source/ThirdParty/**',
- '!Source/Workers/cesiumWorkerBootstrapper.js',
- 'Apps/**/*.js',
- 'Apps/Sandcastle/gallery/*.html',
- '!Apps/Sandcastle/ThirdParty/**',
- 'Specs/**/*.js',
- 'Tools/buildTasks/**/*.js',
- 'gulpfile.js'];
- var filesToClean = ['Source/Cesium.js',
- 'Build',
- 'Instrumented',
- 'Source/Shaders/**/*.js',
- 'Specs/SpecList.js',
- 'Apps/Sandcastle/jsHintOptions.js',
- 'Apps/Sandcastle/gallery/gallery-index.js',
- 'Cesium-*.zip'];
- var filesToSortRequires = ['Source/**/*.js',
- '!Source/Shaders/**',
- '!Source/ThirdParty/**',
- '!Source/Workers/cesiumWorkerBootstrapper.js',
- '!Source/copyrightHeader.js',
- '!Source/Workers/transferTypedArrayTest.js',
- 'Apps/**/*.js',
- '!Apps/Sandcastle/ThirdParty/**',
- '!Apps/Sandcastle/jsHintOptions.js',
- 'Specs/**/*.js',
- '!Specs/spec-main.js',
- '!Specs/SpecRunner.js',
- '!Specs/SpecList.js',
- '!Specs/karma.conf.js',
- '!Apps/Sandcastle/Sandcastle-client.js',
- '!Apps/Sandcastle/Sandcastle-header.js',
- '!Apps/Sandcastle/Sandcastle-warn.js',
- '!Apps/Sandcastle/gallery/gallery-index.js'];
- gulp.task('default', ['combine']);
- gulp.task('build', function(done) {
- mkdirp.sync('Build');
- glslToJavaScript(minifyShaders, 'Build/minifyShaders.state');
- createCesiumJs();
- createSpecList();
- createGalleryList();
- createJsHintOptions();
- done();
- });
- gulp.task('build-watch', function() {
- gulp.watch(buildFiles, ['build']);
- });
- gulp.task('buildApps', function() {
- return buildCesiumViewer();
- });
- gulp.task('clean', function(done) {
- filesToClean.forEach(function(file) {
- rimraf.sync(file);
- });
- done();
- });
- gulp.task('requirejs', function(done) {
- var config = JSON.parse(new Buffer(process.argv[3].substring(2), 'base64').toString('utf8'));
- requirejs.optimize(config, function() {
- done();
- }, done);
- });
- gulp.task('cloc', ['build'], function() {
- var cmdLine;
- var clocPath = path.join('Tools', 'cloc-1.60', 'cloc-1.60.pl');
- var cloc_definitions = path.join('Tools', 'cloc-1.60', 'cloc_definitions');
- //Run cloc on primary Source files only
- var source = new Promise(function(resolve, reject) {
- var glsl = globby.sync(['Source/Shaders/*.glsl', 'Source/Shaders/**/*.glsl']).join(' ');
- cmdLine = 'perl ' + clocPath + ' --quiet --progress-rate=0 --read-lang-def=' + cloc_definitions +
- ' Source/main.js Source/Core/ Source/DataSources/ Source/Renderer/ Source/Scene/ Source/Widgets/ Source/Workers/ ' + glsl;
- child_process.exec(cmdLine, function(error, stdout, stderr) {
- if (error) {
- console.log(stderr);
- return reject(error);
- }
- console.log('Source:');
- console.log(stdout);
- resolve();
- });
- });
- //If running cloc on source succeeded, also run it on the tests.
- return source.then(function() {
- return new Promise(function(resolve, reject) {
- cmdLine = 'perl ' + clocPath + ' --quiet --progress-rate=0 --read-lang-def=' + cloc_definitions + ' Specs/';
- child_process.exec(cmdLine, function(error, stdout, stderr) {
- if (error) {
- console.log(stderr);
- return reject(error);
- }
- console.log('Specs:');
- console.log(stdout);
- resolve();
- });
- });
- });
- });
- gulp.task('combine', ['generateStubs'], function() {
- var outputDirectory = path.join('Build', 'CesiumUnminified');
- return combineJavaScript({
- removePragmas : false,
- optimizer : 'none',
- outputDirectory : outputDirectory
- });
- });
- gulp.task('combineRelease', ['generateStubs'], function() {
- var outputDirectory = path.join('Build', 'CesiumUnminified');
- return combineJavaScript({
- removePragmas : true,
- optimizer : 'none',
- outputDirectory : outputDirectory
- });
- });
- //Builds the documentation
- gulp.task('generateDocumentation', function() {
- var envPathSeperator = os.platform() === 'win32' ? ';' : ':';
- return new Promise(function(resolve, reject) {
- child_process.exec('jsdoc --configure Tools/jsdoc/conf.json', {
- env : {
- PATH : process.env.PATH + envPathSeperator + 'node_modules/.bin',
- CESIUM_VERSION : version
- }
- }, function(error, stdout, stderr) {
- if (error) {
- console.log(stderr);
- return reject(error);
- }
- console.log(stdout);
- var stream = gulp.src('Documentation/Images/**').pipe(gulp.dest('Build/Documentation/Images'));
- return streamToPromise(stream).then(resolve);
- });
- });
- });
- gulp.task('instrumentForCoverage', ['build'], function(done) {
- var jscoveragePath = path.join('Tools', 'jscoverage-0.5.1', 'jscoverage.exe');
- var cmdLine = jscoveragePath + ' Source Instrumented --no-instrument=./ThirdParty';
- child_process.exec(cmdLine, function(error, stdout, stderr) {
- if (error) {
- console.log(stderr);
- return done(error);
- }
- console.log(stdout);
- done();
- });
- });
- gulp.task('jsHint', ['build'], function() {
- var stream = gulp.src(jsHintFiles)
- .pipe(jshint.extract('auto'))
- .pipe(jshint())
- .pipe(jshint.reporter('jshint-stylish'));
- if (yargs.argv.failTaskOnError) {
- stream = stream.pipe(jshint.reporter('fail'));
- }
- return stream;
- });
- gulp.task('jsHint-watch', function() {
- gulp.watch(jsHintFiles).on('change', function(event) {
- gulp.src(event.path)
- .pipe(jshint.extract('auto'))
- .pipe(jshint())
- .pipe(jshint.reporter('jshint-stylish'));
- });
- });
- gulp.task('makeZipFile', ['release'], function() {
- //For now we regenerate the JS glsl to force it to be unminified in the release zip
- //See https://github.com/AnalyticalGraphicsInc/cesium/pull/3106#discussion_r42793558 for discussion.
- glslToJavaScript(false, 'Build/minifyShaders.state');
- var builtSrc = gulp.src([
- 'Build/Apps/**',
- 'Build/Cesium/**',
- 'Build/CesiumUnminified/**',
- 'Build/Documentation/**'
- ], {
- base : '.'
- });
- var staticSrc = gulp.src([
- 'Apps/**',
- '!Apps/Sandcastle/gallery/development/**',
- 'Source/**',
- 'Specs/**',
- 'ThirdParty/**',
- 'logo.png',
- 'favicon.ico',
- 'gulpfile.js',
- 'server.js',
- 'package.json',
- 'LICENSE.md',
- 'CHANGES.md',
- 'README.md',
- 'web.config'
- ], {
- base : '.',
- nodir : true
- });
- var indexSrc = gulp.src('index.release.html').pipe(gulpRename("index.html"));
- return eventStream.merge(builtSrc, staticSrc, indexSrc)
- .pipe(gulpZip('Cesium-' + version + '.zip'))
- .pipe(gulp.dest('.'));
- });
- gulp.task('minify', ['generateStubs'], function() {
- return combineJavaScript({
- removePragmas : false,
- optimizer : 'uglify2',
- outputDirectory : path.join('Build', 'Cesium')
- });
- });
- gulp.task('minifyRelease', ['generateStubs'], function() {
- return combineJavaScript({
- removePragmas : true,
- optimizer : 'uglify2',
- outputDirectory : path.join('Build', 'Cesium')
- });
- });
- function isTravisPullRequest() {
- return process.env.TRAVIS_PULL_REQUEST !== undefined && process.env.TRAVIS_PULL_REQUEST !== 'false';
- }
- gulp.task('deploy-s3', function(done) {
- if (isTravisPullRequest()) {
- console.log('Skipping deployment for non-pull request.');
- return;
- }
- var argv = yargs.usage('Usage: delpoy -b [Bucket Name] -d [Upload Directory]')
- .demand(['b', 'd']).argv;
- var uploadDirectory = argv.d;
- var bucketName = argv.b;
- var cacheControl = argv.c ? argv.c : 'max-age=3600';
- if (argv.confirm) {
- // skip prompt for travis
- deployCesium(bucketName, uploadDirectory, cacheControl, done);
- return;
- }
- var iface = readline.createInterface({
- input: process.stdin,
- output: process.stdout
- });
- // prompt for confirmation
- iface.question('Files from your computer will be published to the ' + bucketName + ' bucket. Continue? [y/n] ', function(answer) {
- iface.close();
- if (answer === 'y') {
- deployCesium(bucketName, uploadDirectory, cacheControl, done);
- } else {
- console.log('Deploy aborted by user.');
- done();
- }
- });
- });
- // Deploy cesium to s3
- function deployCesium(bucketName, uploadDirectory, cacheControl, done) {
- var readFile = Promise.promisify(fs.readFile);
- var gzip = Promise.promisify(zlib.gzip);
- var getCredentials = Promise.promisify(aws.config.getCredentials, {context: aws.config});
- var concurrencyLimit = 2000;
- var s3 = new Promise.promisifyAll(new aws.S3({
- maxRetries : 10,
- retryDelayOptions : {
- base : 500
- }
- }));
- var existingBlobs = [];
- var totalFiles = 0;
- var uploaded = 0;
- var skipped = 0;
- var errors = [];
- return getCredentials()
- .then(function() {
- var prefix = uploadDirectory + '/';
- return listAll(s3, bucketName, prefix, existingBlobs)
- .then(function() {
- return globby([
- 'Apps/**',
- 'Build/**',
- 'Source/**',
- 'Specs/**',
- 'ThirdParty/**',
- '*.md',
- 'favicon.ico',
- 'gulpfile.js',
- 'index.html',
- 'logo.png',
- 'package.json',
- 'server.js',
- 'web.config',
- '*.zip',
- '*.tgz'
- ], {
- dot : true, // include hidden files
- nodir : true // only directory files
- });
- })
- .then(function(files) {
- return Promise.map(files, function(file) {
- var blobName = uploadDirectory + '/' + file;
- var mimeLookup = getMimeType(blobName);
- var contentType = mimeLookup.type;
- var compress = mimeLookup.compress;
- var contentEncoding = compress ? 'gzip' : undefined;
- var etag;
- totalFiles++;
- return readFile(file)
- .then(function(content) {
- return compress ? gzip(content) : content;
- })
- .then(function(content) {
- // compute hash and etag
- var hash = crypto.createHash('md5').update(content).digest('hex');
- etag = crypto.createHash('md5').update(content).digest('base64');
- var index = existingBlobs.indexOf(blobName);
- if (index <= -1) {
- return content;
- }
- // remove files as we find them on disk
- existingBlobs.splice(index, 1);
- // get file info
- return s3.headObjectAsync({
- Bucket : bucketName,
- Key : blobName
- })
- .then(function(data) {
- if (data.ETag !== ('"' + hash + '"') ||
- data.CacheControl !== cacheControl ||
- data.ContentType !== contentType ||
- data.ContentEncoding !== contentEncoding) {
- return content;
- }
- // We don't need to upload this file again
- skipped++;
- return undefined;
- })
- .catch(function(error) {
- errors.push(error);
- });
- })
- .then(function(content) {
- if (!content) {
- return;
- }
- console.log('Uploading ' + blobName + '...');
- var params = {
- Bucket : bucketName,
- Key : blobName,
- Body : content,
- ContentMD5 : etag,
- ContentType : contentType,
- ContentEncoding : contentEncoding,
- CacheControl : cacheControl
- };
- return s3.putObjectAsync(params).then(function() {
- uploaded++;
- })
- .catch(function(error) {
- errors.push(error);
- });
- });
- }, {concurrency : concurrencyLimit});
- })
- .then(function() {
- console.log('Skipped ' + skipped + ' files and successfully uploaded ' + uploaded + ' files of ' + (totalFiles - skipped) + ' files.');
- if (existingBlobs.length === 0) {
- return;
- }
- var objectToDelete = [];
- existingBlobs.forEach(function(file) {
- //Don't delete generate zip files.
- if (!/\.(zip|tgz)$/.test(file)) {
- objectToDelete.push({Key : file});
- }
- });
- if (objectToDelete.length > 0) {
- console.log('Cleaning up old files...');
- return s3.deleteObjectsAsync({
- Bucket : bucketName,
- Delete : {
- Objects : objectToDelete
- }
- })
- .then(function() {
- console.log('Cleaned ' + existingBlobs.length + ' files.');
- });
- }
- })
- .catch(function(error) {
- errors.push(error);
- })
- .then(function() {
- if (errors.length === 0) {
- done();
- return;
- }
- console.log('Errors: ');
- errors.map(function(e) {
- console.log(e);
- });
- done(1);
- });
- })
- .catch(function(error) {
- console.log('Error: Could not load S3 credentials.');
- done();
- });
- }
- function getMimeType(filename) {
- var ext = path.extname(filename);
- if (ext === '.bin' || ext === '.terrain') {
- return { type : 'application/octet-stream', compress : true };
- } else if (ext === '.md' || ext === '.glsl') {
- return { type : 'text/plain', compress : true };
- } else if (ext === '.czml' || ext === '.geojson' || ext === '.json') {
- return { type : 'application/json', compress : true };
- } else if (ext === '.js') {
- return { type : 'application/javascript', compress : true };
- } else if (ext === '.svg') {
- return { type : 'image/svg+xml', compress : true };
- } else if (ext === '.woff') {
- return { type : 'application/font-woff', compress : false };
- }
- var mimeType = mime.lookup(filename);
- return {type : mimeType, compress : compressible(mimeType)};
- }
- // get all files currently in bucket asynchronously
- function listAll(s3, bucketName, prefix, files, marker) {
- return s3.listObjectsAsync({
- Bucket : bucketName,
- MaxKeys : 1000,
- Prefix : prefix,
- Marker : marker
- })
- .then(function(data) {
- var items = data.Contents;
- for (var i = 0; i < items.length; i++) {
- files.push(items[i].Key);
- }
- if (data.IsTruncated) {
- // get next page of results
- return listAll(s3, bucketName, prefix, files, files[files.length - 1]);
- }
- });
- }
- gulp.task('deploy-set-version', function() {
- var version = yargs.argv.version;
- if (version) {
- packageJson.version += '-' + version;
- fs.writeFileSync('package.json', JSON.stringify(packageJson, undefined, 2));
- }
- });
- gulp.task('deploy-status', function() {
- if (isTravisPullRequest()) {
- console.log('Skipping deployment status for non-pull request.');
- return;
- }
- var status = yargs.argv.status;
- var message = yargs.argv.message;
- var deployUrl = travisDeployUrl + process.env.TRAVIS_BRANCH + '/';
- var zipUrl = deployUrl + 'Cesium-' + packageJson.version + '.zip';
- var npmUrl = deployUrl + 'cesium-' + packageJson.version + '.tgz';
- return Promise.join(
- setStatus(status, deployUrl, message, 'deployment'),
- setStatus(status, zipUrl, message, 'zip file'),
- setStatus(status, npmUrl, message, 'npm package')
- );
- });
- function setStatus(state, targetUrl, description, context) {
- // skip if the environment does not have the token
- if (!process.env.TOKEN) {
- return;
- }
- var requestPost = Promise.promisify(request.post);
- return requestPost({
- url: 'https://api.github.com/repos/' + process.env.TRAVIS_REPO_SLUG + '/statuses/' + process.env.TRAVIS_COMMIT,
- json: true,
- headers: {
- 'Authorization': 'token ' + process.env.TOKEN,
- 'User-Agent': 'Cesium'
- },
- body: {
- state: state,
- target_url: targetUrl,
- description: description,
- context: context
- }
- });
- }
- gulp.task('release', ['combine', 'minifyRelease', 'generateDocumentation']);
- gulp.task('test', function(done) {
- var argv = yargs.argv;
- var enableAllBrowsers = argv.all ? true : false;
- var includeCategory = argv.include ? argv.include : '';
- var excludeCategory = argv.exclude ? argv.exclude : '';
- var webglValidation = argv.webglValidation ? argv.webglValidation : false;
- var release = argv.release ? argv.release : false;
- var failTaskOnError = argv.failTaskOnError ? argv.failTaskOnError : false;
- var suppressPassed = argv.suppressPassed ? argv.suppressPassed : false;
- var browsers = ['Chrome'];
- if (argv.browsers) {
- browsers = argv.browsers.split(',');
- }
- var files = [
- 'Specs/karma-main.js',
- {pattern : 'Source/**', included : false},
- {pattern : 'Specs/**', included : false}
- ];
- if (release) {
- files.push({pattern : 'Build/**', included : false});
- }
- karma.start({
- configFile: karmaConfigFile,
- browsers : browsers,
- specReporter: {
- suppressErrorSummary: false,
- suppressFailed: false,
- suppressPassed: suppressPassed,
- suppressSkipped: true
- },
- detectBrowsers : {
- enabled: enableAllBrowsers
- },
- files: files,
- client: {
- args: [includeCategory, excludeCategory, webglValidation, release]
- }
- }, function(e) {
- return done(failTaskOnError ? e : undefined);
- });
- });
- gulp.task('generateStubs', ['build'], function(done) {
- mkdirp.sync(path.join('Build', 'Stubs'));
- var contents = '\
- /*global define,Cesium*/\n\
- (function() {\n\
- \'use strict\';\n\
- /*jshint sub:true*/\n';
- var modulePathMappings = [];
- globby.sync(sourceFiles).forEach(function(file) {
- file = path.relative('Source', file);
- var moduleId = filePathToModuleId(file);
- contents += '\
- define(\'' + moduleId + '\', function() {\n\
- return Cesium[\'' + path.basename(file, path.extname(file)) + '\'];\n\
- });\n\n';
- modulePathMappings.push(' \'' + moduleId + '\' : \'../Stubs/Cesium\'');
- });
- contents += '})();';
- var paths = '\
- /*global define*/\n\
- define(function() {\n\
- \'use strict\';\n\
- return {\n' + modulePathMappings.join(',\n') + '\n\
- };\n\
- });';
- fs.writeFileSync(path.join('Build', 'Stubs', 'Cesium.js'), contents);
- fs.writeFileSync(path.join('Build', 'Stubs', 'paths.js'), paths);
- done();
- });
- gulp.task('sortRequires', function() {
- var noModulesRegex = /[\s\S]*?define\(function\(\)/;
- var requiresRegex = /([\s\S]*?(define|defineSuite|require)\((?:{[\s\S]*}, )?\[)([\S\s]*?)]([\s\S]*?function\s*)\(([\S\s]*?)\) {([\s\S]*)/;
- var splitRegex = /,\s*/;
- var fsReadFile = Promise.promisify(fs.readFile);
- var fsWriteFile = Promise.promisify(fs.writeFile);
- var files = globby.sync(filesToSortRequires);
- return Promise.map(files, function(file) {
- return fsReadFile(file).then(function(contents) {
- var result = requiresRegex.exec(contents);
- if (result === null) {
- if (!noModulesRegex.test(contents)) {
- console.log(file + ' does not have the expected syntax.');
- }
- return;
- }
- // In specs, the first require is significant,
- // unless the spec is given an explicit name.
- var preserveFirst = false;
- if (result[2] === 'defineSuite' && result[4] === ', function') {
- preserveFirst = true;
- }
- var names = result[3].split(splitRegex);
- if (names.length === 1 && names[0].trim() === '') {
- names.length = 0;
- }
- var i;
- for (i = 0; i < names.length; ++i) {
- if (names[i].indexOf('//') >= 0 || names[i].indexOf('/*') >= 0) {
- console.log(file + ' contains comments in the require list. Skipping so nothing gets broken.');
- return;
- }
- }
- var identifiers = result[5].split(splitRegex);
- if (identifiers.length === 1 && identifiers[0].trim() === '') {
- identifiers.length = 0;
- }
- for (i = 0; i < identifiers.length; ++i) {
- if (identifiers[i].indexOf('//') >= 0 || identifiers[i].indexOf('/*') >= 0) {
- console.log(file + ' contains comments in the require list. Skipping so nothing gets broken.');
- return;
- }
- }
- var requires = [];
- for (i = preserveFirst ? 1 : 0; i < names.length && i < identifiers.length; ++i) {
- requires.push({
- name : names[i].trim(),
- identifier : identifiers[i].trim()
- });
- }
- requires.sort(function(a, b) {
- var aName = a.name.toLowerCase();
- var bName = b.name.toLowerCase();
- if (aName < bName) {
- return -1;
- } else if (aName > bName) {
- return 1;
- } else {
- return 0;
- }
- });
- if (preserveFirst) {
- requires.splice(0, 0, {
- name : names[0].trim(),
- identifier : identifiers[0].trim()
- });
- }
- // Convert back to separate lists for the names and identifiers, and add
- // any additional names or identifiers that don't have a corresponding pair.
- var sortedNames = requires.map(function(item) {
- return item.name;
- });
- for (i = sortedNames.length; i < names.length; ++i) {
- sortedNames.push(names[i].trim());
- }
- var sortedIdentifiers = requires.map(function(item) {
- return item.identifier;
- });
- for (i = sortedIdentifiers.length; i < identifiers.length; ++i) {
- sortedIdentifiers.push(identifiers[i].trim());
- }
- var outputNames = ']';
- if (sortedNames.length > 0) {
- outputNames = os.EOL + ' ' +
- sortedNames.join(',' + os.EOL + ' ') +
- os.EOL + ' ]';
- }
- var outputIdentifiers = '(';
- if (sortedIdentifiers.length > 0) {
- outputIdentifiers = '(' + os.EOL + ' ' +
- sortedIdentifiers.join(',' + os.EOL + ' ');
- }
- contents = result[1] +
- outputNames +
- result[4].replace(/^[,\s]+/, ', ').trim() +
- outputIdentifiers +
- ') {' +
- result[6];
- return fsWriteFile(file, contents);
- });
- });
- });
- function combineCesium(debug, optimizer, combineOutput) {
- return requirejsOptimize('Cesium.js', {
- wrap : true,
- useStrict : true,
- optimize : optimizer,
- optimizeCss : 'standard',
- pragmas : {
- debug : debug
- },
- baseUrl : 'Source',
- skipModuleInsertion : true,
- name : removeExtension(path.relative('Source', require.resolve('almond'))),
- include : 'main',
- out : path.join(combineOutput, 'Cesium.js')
- });
- }
- function combineWorkers(debug, optimizer, combineOutput) {
- //This is done waterfall style for concurrency reasons.
- return globby(['Source/Workers/cesiumWorkerBootstrapper.js',
- 'Source/Workers/transferTypedArrayTest.js',
- 'Source/ThirdParty/Workers/*.js'])
- .then(function(files) {
- return Promise.map(files, function(file) {
- return requirejsOptimize(file, {
- wrap : false,
- useStrict : true,
- optimize : optimizer,
- optimizeCss : 'standard',
- pragmas : {
- debug : debug
- },
- baseUrl : 'Source',
- skipModuleInsertion : true,
- include : filePathToModuleId(path.relative('Source', file)),
- out : path.join(combineOutput, path.relative('Source', file))
- });
- }, {concurrency : concurrency});
- })
- .then(function() {
- return globby(['Source/Workers/*.js',
- '!Source/Workers/cesiumWorkerBootstrapper.js',
- '!Source/Workers/transferTypedArrayTest.js',
- '!Source/Workers/createTaskProcessorWorker.js',
- '!Source/ThirdParty/Workers/*.js']);
- })
- .then(function(files) {
- return Promise.map(files, function(file) {
- return requirejsOptimize(file, {
- wrap : true,
- useStrict : true,
- optimize : optimizer,
- optimizeCss : 'standard',
- pragmas : {
- debug : debug
- },
- baseUrl : 'Source',
- include : filePathToModuleId(path.relative('Source', file)),
- out : path.join(combineOutput, path.relative('Source', file))
- });
- }, {concurrency : concurrency});
- });
- }
- function minifyCSS(outputDirectory) {
- return globby('Source/**/*.css').then(function(files) {
- return Promise.map(files, function(file) {
- return requirejsOptimize(file, {
- wrap : true,
- useStrict : true,
- optimizeCss : 'standard',
- pragmas : {
- debug : true
- },
- cssIn : file,
- out : path.join(outputDirectory, path.relative('Source', file))
- });
- }, {concurrency : concurrency});
- });
- }
- function combineJavaScript(options) {
- var optimizer = options.optimizer;
- var outputDirectory = options.outputDirectory;
- var removePragmas = options.removePragmas;
- var combineOutput = path.join('Build', 'combineOutput', optimizer);
- var copyrightHeader = fs.readFileSync(path.join('Source', 'copyrightHeader.js'));
- var promise = Promise.join(
- combineCesium(!removePragmas, optimizer, combineOutput),
- combineWorkers(!removePragmas, optimizer, combineOutput)
- );
- return promise.then(function() {
- var promises = [];
- //copy to build folder with copyright header added at the top
- var stream = gulp.src([combineOutput + '/**'])
- .pipe(gulpInsert.prepend(copyrightHeader))
- .pipe(gulp.dest(outputDirectory));
- promises.push(streamToPromise(stream));
- var everythingElse = ['Source/**', '!**/*.js', '!**/*.glsl'];
- if (optimizer === 'uglify2') {
- promises.push(minifyCSS(outputDirectory));
- everythingElse.push('!**/*.css');
- }
- stream = gulp.src(everythingElse, {nodir : true}).pipe(gulp.dest(outputDirectory));
- promises.push(streamToPromise(stream));
- return Promise.all(promises).then(function() {
- rimraf.sync(combineOutput);
- });
- });
- }
- function glslToJavaScript(minify, minifyStateFilePath) {
- fs.writeFileSync(minifyStateFilePath, minify);
- var minifyStateFileLastModified = fs.existsSync(minifyStateFilePath) ? fs.statSync(minifyStateFilePath).mtime.getTime() : 0;
- // collect all currently existing JS files into a set, later we will remove the ones
- // we still are using from the set, then delete any files remaining in the set.
- var leftOverJsFiles = {};
- globby.sync(['Source/Shaders/**/*.js']).forEach(function(file) {
- leftOverJsFiles[path.normalize(file)] = true;
- });
- var builtinFunctions = [];
- var builtinConstants = [];
- var builtinStructs = [];
- var glslFiles = globby.sync(['Source/Shaders/**/*.glsl']);
- glslFiles.forEach(function(glslFile) {
- glslFile = path.normalize(glslFile);
- var baseName = path.basename(glslFile, '.glsl');
- var jsFile = path.join(path.dirname(glslFile), baseName) + '.js';
- // identify built in functions, structs, and constants
- var baseDir = path.join('Source', 'Shaders', 'Builtin');
- if (glslFile.indexOf(path.normalize(path.join(baseDir, 'Functions'))) === 0) {
- builtinFunctions.push(baseName);
- }
- else if (glslFile.indexOf(path.normalize(path.join(baseDir, 'Constants'))) === 0) {
- builtinConstants.push(baseName);
- }
- else if (glslFile.indexOf(path.normalize(path.join(baseDir, 'Structs'))) === 0) {
- builtinStructs.push(baseName);
- }
- delete leftOverJsFiles[jsFile];
- var jsFileExists = fs.existsSync(jsFile);
- var jsFileModified = jsFileExists ? fs.statSync(jsFile).mtime.getTime() : 0;
- var glslFileModified = fs.statSync(glslFile).mtime.getTime();
- if (jsFileExists && jsFileModified > glslFileModified && jsFileModified > minifyStateFileLastModified) {
- return;
- }
- var contents = fs.readFileSync(glslFile, 'utf8');
- contents = contents.replace(/\r\n/gm, '\n');
- var copyrightComments = '';
- var extractedCopyrightComments = contents.match(/\/\*\*(?:[^*\/]|\*(?!\/)|\n)*?@license(?:.|\n)*?\*\//gm);
- if (extractedCopyrightComments) {
- copyrightComments = extractedCopyrightComments.join('\n') + '\n';
- }
- if (minify) {
- contents = stripComments(contents);
- contents = contents.replace(/\s+$/gm, '').replace(/^\s+/gm, '').replace(/\n+/gm, '\n');
- contents += '\n';
- }
- contents = contents.split('"').join('\\"').replace(/\n/gm, '\\n\\\n');
- contents = copyrightComments + '\
- //This file is automatically rebuilt by the Cesium build process.\n\
- /*global define*/\n\
- define(function() {\n\
- \'use strict\';\n\
- return "' + contents + '";\n\
- });';
- fs.writeFileSync(jsFile, contents);
- });
- // delete any left over JS files from old shaders
- Object.keys(leftOverJsFiles).forEach(function(filepath) {
- rimraf.sync(filepath);
- });
- var generateBuiltinContents = function(contents, builtins, path) {
- var amdPath = contents.amdPath;
- var amdClassName = contents.amdClassName;
- var builtinLookup = contents.builtinLookup;
- for (var i = 0; i < builtins.length; i++) {
- var builtin = builtins[i];
- amdPath = amdPath + ',\n \'./' + path + '/' + builtin + '\'';
- amdClassName = amdClassName + ',\n ' + 'czm_' + builtin;
- builtinLookup = builtinLookup + ',\n ' + 'czm_' + builtin + ' : ' + 'czm_' + builtin;
- }
- contents.amdPath = amdPath;
- contents.amdClassName = amdClassName;
- contents.builtinLookup = builtinLookup;
- };
- //generate the JS file for Built-in GLSL Functions, Structs, and Constants
- var contents = {amdPath : '', amdClassName : '', builtinLookup : ''};
- generateBuiltinContents(contents, builtinConstants, 'Constants');
- generateBuiltinContents(contents, builtinStructs, 'Structs');
- generateBuiltinContents(contents, builtinFunctions, 'Functions');
- contents.amdPath = contents.amdPath.replace(',\n', '');
- contents.amdClassName = contents.amdClassName.replace(',\n', '');
- contents.builtinLookup = contents.builtinLookup.replace(',\n', '');
- var fileContents = '\
- //This file is automatically rebuilt by the Cesium build process.\n\
- /*global define*/\n\
- define([\n' +
- contents.amdPath +
- '\n ], function(\n' +
- contents.amdClassName +
- ') {\n\
- \'use strict\';\n\
- return {\n' + contents.builtinLookup + '};\n\
- });';
- fs.writeFileSync(path.join('Source', 'Shaders', 'Builtin', 'CzmBuiltins.js'), fileContents);
- }
- function createCesiumJs() {
- var moduleIds = [];
- var parameters = [];
- var assignments = [];
- var nonIdentifierRegexp = /[^0-9a-zA-Z_$]/g;
- globby.sync(sourceFiles).forEach(function(file) {
- file = path.relative('Source', file);
- var moduleId = file;
- moduleId = filePathToModuleId(moduleId);
- var assignmentName = "['" + path.basename(file, path.extname(file)) + "']";
- if (moduleId.indexOf('Shaders/') === 0) {
- assignmentName = '._shaders' + assignmentName;
- }
- var parameterName = moduleId.replace(nonIdentifierRegexp, '_');
- moduleIds.push("'./" + moduleId + "'");
- parameters.push(parameterName);
- assignments.push('Cesium' + assignmentName + ' = ' + parameterName + ';');
- });
- var contents = '\
- /*global define*/\n\
- define([' + moduleIds.join(', ') + '], function(' + parameters.join(', ') + ') {\n\
- \'use strict\';\n\
- /*jshint sub:true*/\n\
- var Cesium = {\n\
- VERSION : "' + version + '",\n\
- _shaders : {}\n\
- };\n\
- ' + assignments.join('\n ') + '\n\
- return Cesium;\n\
- });';
- fs.writeFileSync('Source/Cesium.js', contents);
- }
- function createSpecList() {
- var specFiles = globby.sync(['Specs/**/*.js', '!Specs/*.js']);
- var specs = [];
- specFiles.forEach(function(file) {
- specs.push("'" + filePathToModuleId(file) + "'");
- });
- var contents = '/*jshint unused: false*/\nvar specs = [' + specs.join(',') + '];';
- fs.writeFileSync(path.join('Specs', 'SpecList.js'), contents);
- }
- function createGalleryList() {
- var demoObjects = [];
- var demoJSONs = [];
- var output = path.join('Apps', 'Sandcastle', 'gallery', 'gallery-index.js');
- var fileList = ['Apps/Sandcastle/gallery/**/*.html'];
- if (noDevelopmentGallery) {
- fileList.push('!Apps/Sandcastle/gallery/development/**/*.html');
- }
- globby.sync(fileList).forEach(function(file) {
- var demo = filePathToModuleId(path.relative('Apps/Sandcastle/gallery', file));
- var demoObject = {
- name : demo,
- date : fs.statSync(file).mtime.getTime()
- };
- if (fs.existsSync(file.replace('.html', '') + '.jpg')) {
- demoObject.img = demo + '.jpg';
- }
- demoObjects.push(demoObject);
- });
- demoObjects.sort(function(a, b) {
- if (a.name < b.name) {
- return -1;
- } else if (a.name > b.name) {
- return 1;
- } else {
- return 0;
- }
- });
- var i;
- for (i = 0; i < demoObjects.length; ++i) {
- demoJSONs[i] = JSON.stringify(demoObjects[i], null, 2);
- }
- var contents = '\
- // This file is automatically rebuilt by the Cesium build process.\n\
- var gallery_demos = [' + demoJSONs.join(', ') + '];';
- fs.writeFileSync(output, contents);
- }
- function createJsHintOptions() {
- var primary = JSON.parse(fs.readFileSync('.jshintrc', 'utf8'));
- var gallery = JSON.parse(fs.readFileSync(path.join('Apps', 'Sandcastle', '.jshintrc'), 'utf8'));
- primary.jasmine = false;
- primary.predef = gallery.predef;
- primary.unused = gallery.unused;
- var contents = '\
- // This file is automatically rebuilt by the Cesium build process.\n\
- var sandcastleJsHintOptions = ' + JSON.stringify(primary, null, 4) + ';';
- fs.writeFileSync(path.join('Apps', 'Sandcastle', 'jsHintOptions.js'), contents);
- }
- function buildCesiumViewer() {
- var cesiumViewerOutputDirectory = 'Build/Apps/CesiumViewer';
- var cesiumViewerStartup = path.join(cesiumViewerOutputDirectory, 'CesiumViewerStartup.js');
- var cesiumViewerCss = path.join(cesiumViewerOutputDirectory, 'CesiumViewer.css');
- mkdirp.sync(cesiumViewerOutputDirectory);
- var promise = Promise.join(
- requirejsOptimize('CesiumViewer', {
- wrap : true,
- useStrict : true,
- optimizeCss : 'standard',
- pragmas : {
- debug : false
- },
- optimize : 'uglify2',
- mainConfigFile : 'Apps/CesiumViewer/CesiumViewerStartup.js',
- name : 'CesiumViewerStartup',
- out : cesiumViewerStartup
- }),
- requirejsOptimize('CesiumViewer CSS', {
- wrap : true,
- useStrict : true,
- optimizeCss : 'standard',
- pragmas : {
- debug : false
- },
- cssIn : 'Apps/CesiumViewer/CesiumViewer.css',
- out : cesiumViewerCss
- })
- );
- promise = promise.then(function() {
- var copyrightHeader = fs.readFileSync(path.join('Source', 'copyrightHeader.js'));
- var stream = eventStream.merge(
- gulp.src(cesiumViewerStartup)
- .pipe(gulpInsert.prepend(copyrightHeader))
- .pipe(gulpReplace('../../Source', '.'))
- .pipe(gulpReplace('../../ThirdParty/requirejs-2.1.20', '.')),
- gulp.src(cesiumViewerCss)
- .pipe(gulpReplace('../../Source', '.')),
- gulp.src(['Apps/CesiumViewer/index.html'])
- .pipe(gulpReplace('../../ThirdParty/requirejs-2.1.20', '.')),
- gulp.src(['Apps/CesiumViewer/**',
- '!Apps/CesiumViewer/index.html',
- '!Apps/CesiumViewer/**/*.js',
- '!Apps/CesiumViewer/**/*.css']),
- gulp.src(['ThirdParty/requirejs-2.1.20/require.min.js'])
- .pipe(gulpRename('require.js')),
- gulp.src(['Build/Cesium/Assets/**',
- 'Build/Cesium/Workers/**',
- 'Build/Cesium/ThirdParty/Workers/**',
- 'Build/Cesium/Widgets/**',
- '!Build/Cesium/Widgets/**/*.css'],
- {
- base : 'Build/Cesium',
- nodir : true
- }),
- gulp.src(['Build/Cesium/Widgets/InfoBox/InfoBoxDescription.css'], {
- base : 'Build/Cesium'
- }),
- gulp.src(['web.config'])
- );
- return streamToPromise(stream.pipe(gulp.dest(cesiumViewerOutputDirectory)));
- });
- return promise;
- }
- function filePathToModuleId(moduleId) {
- return moduleId.substring(0, moduleId.lastIndexOf('.')).replace(/\\/g, '/');
- }
- function removeExtension(p) {
- return p.slice(0, -path.extname(p).length);
- }
- function requirejsOptimize(name, config) {
- console.log('Building ' + name);
- return new Promise(function(resolve, reject) {
- var cmd = 'npm run requirejs -- --' + new Buffer(JSON.stringify(config)).toString('base64') + ' --silent';
- child_process.exec(cmd, function(e) {
- if (e) {
- console.log('Error ' + name);
- reject(e);
- return;
- }
- console.log('Finished ' + name);
- resolve();
- });
- });
- }
- function streamToPromise(stream) {
- return new Promise(function(resolve, reject) {
- stream.on('finish', resolve);
- stream.on('end', reject);
- });
- }
|