forked from openlayers/openlayers
-
Notifications
You must be signed in to change notification settings - Fork 0
/
build.js
277 lines (252 loc) · 7.03 KB
/
build.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
/**
* This task builds OpenLayers with the Closure Compiler.
*/
var path = require('path');
var async = require('async');
var closure = require('closure-util');
var fse = require('fs-extra');
var fs = require('graceful-fs');
var nomnom = require('nomnom');
var temp = require('temp').track();
var exec = require('child_process').exec;
var generateExports = require('./generate-exports');
var log = closure.log;
var root = path.join(__dirname, '..');
/**
* Assert that a provided config object is valid.
* @param {Object} config Build configuration object.
* @param {function(Error)} callback Called with an error if config is invalid.
*/
function assertValidConfig(config, callback) {
process.nextTick(function() {
if (!Array.isArray(config.exports)) {
callback(new Error('Config missing "exports" array'));
return;
}
if (config.namespace && typeof config.namespace !== 'string') {
callback(new Error('Config "namespace" must be a string'));
return;
}
if (config.compile && typeof config.compile !== 'object') {
callback(new Error('Config "compile" must be an object'));
return;
}
if (config.jvm && !Array.isArray(config.jvm)) {
callback(new Error('Config "jvm" must be an array'));
return;
}
if (config.src && !Array.isArray(config.src)) {
callback(new Error('Config "src" must be an array'));
return;
}
callback(null);
});
}
/**
* Read the build configuration file.
* @param {string} configPath Path to config file.
* @param {function(Error, Object)} callback Callback.
*/
function readConfig(configPath, callback) {
fs.readFile(configPath, function(err, data) {
if (err) {
if (err.code === 'ENOENT') {
err = new Error('Unable to find config file: ' + configPath);
}
callback(err);
return;
}
var config;
try {
config = JSON.parse(String(data));
} catch (err2) {
callback(new Error('Trouble parsing config as JSON: ' + err2.message));
return;
}
callback(null, config);
});
}
/**
* Write the exports code to a temporary file.
* @param {string} exports Exports code.
* @param {function(Error, string)} callback Called with the path to the temp
* file (or any error).
*/
function writeExports(exports, callback) {
temp.open({prefix: 'exports', suffix: '.js'}, function(err, info) {
if (err) {
callback(err);
return;
}
log.verbose('build', 'Writing exports: ' + info.path);
fs.writeFile(info.path, exports, function(err) {
if (err) {
callback(err);
return;
}
fs.close(info.fd, function(err) {
if (err) {
callback(err);
return;
}
callback(null, info.path);
});
});
});
}
/**
* Get the list of sources sorted in dependency order.
* @param {Object} config Build configuration object.
* @param {string} exports Exports code (with goog.exportSymbol calls).
* @param {function(Error, Array.<string>)} callback Called with a list of paths
* or any error.
*/
function getDependencies(config, exports, callback) {
writeExports(exports, function(err, exportsPath) {
if (err) {
callback(err);
return;
}
log.info('ol', 'Parsing dependencies');
var options;
if (config.src) {
options = {
lib: config.src,
cwd: config.cwd
};
} else {
options = {
lib: ['src/**/*.js'],
cwd: root
};
}
closure.getDependencies(options, function(err, paths) {
if (err) {
callback(err);
return;
}
paths.push(exportsPath);
callback(null, paths);
});
});
}
/**
* Concatenate all sources.
* @param {Array.<string>} paths List of paths to source files.
* @param {function(Error, string)} callback Called with the concatenated
* output or any error.
*/
function concatenate(paths, callback) {
async.map(paths, fs.readFile, function(err, results) {
if (err) {
var msg = 'Trouble concatenating sources. ' + err.message;
callback(new Error(msg));
} else {
var preamble = 'var CLOSURE_NO_DEPS = true;\n';
callback(null, preamble + results.join('\n'));
}
});
}
/**
* Run the compiler.
* @param {Object} config Build configuration object.
* @param {Array.<string>} paths List of paths to source files.
* @param {function(Error, string)} callback Called with the compiled output or
* any error.
*/
function build(config, paths, callback) {
var options = {
compile: config.compile,
cwd: config.cwd || root,
jvm: config.jvm
};
if (!options.compile) {
log.info('ol', 'No compile options found. Concatenating ' +
paths.length + ' sources');
concatenate(paths, callback);
} else {
log.info('ol', 'Compiling ' + paths.length + ' sources');
options.compile.js = paths.concat(options.compile.js || []);
closure.compile(options, callback);
}
}
/**
* Adds a file header with the most recent Git tag.
* @param {string} compiledSource The compiled library.
* @param {function(Error, string)} callback Called with the output
* ready to be written into a file, or any error.
*/
function addHeader(compiledSource, callback) {
exec('git describe --tags', function(error, stdout, stderr) {
var header = '// OpenLayers 3. See http://ol3.js.org/\n';
header += '// License: https://raw.githubusercontent.com/openlayers/' +
'ol3/master/LICENSE.md\n';
if (stdout !== '') {
header += '// Version: ' + stdout + '\n';
}
callback(null, header + compiledSource);
});
}
/**
* Generate a build of the library.
* @param {Object} config Build configuration object. Must have an "exports"
* array and a "compile" object with options for the compiler.
* @param {function(Error, string)} callback Called with the compiled source
* or any error.
*/
function main(config, callback) {
async.waterfall([
assertValidConfig.bind(null, config),
generateExports.bind(null, config),
getDependencies.bind(null, config),
build.bind(null, config),
addHeader
], callback);
}
/**
* If running this module directly, read the config file and call the main
* function.
*/
if (require.main === module) {
var options = nomnom.options({
config: {
position: 0,
required: true,
help: 'Path to JSON config file'
},
output: {
position: 1,
required: true,
help: 'Output file path'
},
loglevel: {
abbr: 'l',
choices: ['silly', 'verbose', 'info', 'warn', 'error'],
default: 'info',
help: 'Log level',
metavar: 'LEVEL'
}
}).parse();
/**
* Set the log level.
* @type {string}
*/
log.level = options.loglevel;
// read the config, run the main function, and write the output file
async.waterfall([
readConfig.bind(null, options.config),
main,
fse.outputFile.bind(fse, options.output)
], function(err) {
if (err) {
log.error(err.message);
process.exit(1);
} else {
process.exit(0);
}
});
}
/**
* Export main function.
*/
module.exports = main;