UNPKG

8.64 kBPlain TextView Raw
1#!/usr/bin/env node
2
3
4// Remove any command line information before bower/rc/optimist are loaded and attempt to hijack
5// our CLI args. This is a total hack but works around the issue described here:
6// https://github.com/bower/bower/issues/543
7//
8// This can be removed once bower is updated to 1.9.3 (which updates rc to 0.3.0)
9//
10var args = process.argv.slice(2);
11process.argv = [process.argv[0], process.argv[1]];
12
13process.on('uncaughtException', function(err) {
14 verbose = false;
15
16 if (err.code === 'EMFILE') {
17 console.error('\n\n\tEMFILE error: Too many files open at one time. Fix this by running\n\n\t\tulimit -n 9999\n\n');
18 } else {
19 console.error('Unhandled Exception:', err.stack || err);
20 }
21 process.exit(128);
22});
23
24var _ = require('underscore'),
25 fs = require('fs'),
26 lumbar = require('../lib/lumbar'),
27 dirname = require('path').dirname,
28 growl = require('growl');
29
30var LONG_USAGE="lumbar help\n"+
31" Print this long help message.\n"+
32"lumbar build [--package name] [--config file] [--minimize] [--use path [--with options]] lumbarFile [outputDir]\n"+
33" Build out the package(s).\n"+
34"lumbar watch [--package name] [--config file] [--minimize] [--use path [--with options]] lumbarFile [outputDir]\n"+
35" Start watching the files for changes and rebuild as necessary.\n"+
36"\n"+
37"--package: represents the name of a corresponding package listed\n"+
38" under 'packages' in lumbarFile.\n"+
39"\n"+
40"--module: build only a specific module. May be defined multiple times to build multiple.\n"+
41"\n"+
42"--minimize: to shrink the resultant file.\n"+
43"\n"+
44"--sourceMap: generate a source map for the output modules.\n"+
45" WARN: This copies the source files into the module output unobfuscated.\n"
46" care should be exercised when used with production releases\n"
47"\n"+
48"--config: is the name and path to the lumbar config file, if\n"+
49" not given then lumbar.json is assumed.\n"+
50"\n"+
51"--use: path to your plugin to load\n"+
52"\n"+
53" --with: an optional json config object to pass to your plugin.\n"+
54"\n"+
55" --name: an optional name to assign to your plugin.\n"+
56"\n"+
57"lumbarFile: is the name and path to the lumbar config file, if\n"+
58" not given then lumbar.json is assumed.\n"+
59"\n"+
60"outputDir: Required. Designates where the files will be placed.\n"+
61"\n";
62
63var configFile,
64 packageName,
65 modules = [],
66 libraries = [],
67 minimize = false,
68 sourceMap = false,
69 build = true, // build by default.
70 watch = false,
71 verbose = false,
72 modeSeen;
73
74var lumbarFile = 'lumbar.json';
75var outputDir;
76/**
77 * Import paths.
78 */
79var plugins = [],
80 files = [];
81
82var arg;
83while (args.length) {
84 arg = args.shift();
85
86 var value = arg.split('=');
87 arg = value[0];
88 value = value[1];
89
90 switch (arg) {
91 case '-h':
92 case '--help':
93 console.error(LONG_USAGE);
94 process.exit(0);
95 break;
96 case '-c':
97 case '--config':
98 configFile = args.shift();
99 if (!configFile) throw new Error('--config <file> required');
100 break;
101 case '-p':
102 case '--package':
103 packageName = args.shift();
104 if (!packageName) throw new Error('--package <name> required');
105 break;
106 case '--module':
107 var moduleName = args.shift();
108 if (!moduleName) throw new Error('--module <name> required');
109 modules.push(moduleName);
110 break;
111 case '--library':
112 if (!value) throw new Error('--library=<name> required');
113 libraries.push(value);
114 break;
115 case '-m':
116 case '--minimize':
117 minimize = true;
118 break;
119 case '-s':
120 case '--sourceMap':
121 sourceMap = value || true;
122 break;
123 case '-b':
124 case '--build':
125 case 'build':
126 if (modeSeen) {
127 files.push(arg);
128 } else {
129 modeSeen = true;
130 build = true;
131 watch = false;
132 }
133 break;
134 case '-w':
135 case '--watch':
136 case 'watch':
137 if (modeSeen) {
138 files.push(arg);
139 } else {
140 modeSeen = true;
141 watch = true;
142 build = false;
143 }
144 break;
145 case '-v':
146 case '--verbose':
147 verbose = true;
148 break;
149 case '-u':
150 case '--use':
151 var options;
152 var path = args.shift();
153 if (!path) throw new Error('--use <path> required');
154
155 if ('--with' == args[0]) {
156 args.shift();
157 options = args.shift();
158 if (!options) throw new Error('--with <options> required');
159 try {
160 options = eval('(' + options + ')');
161 } catch (err) {
162 console.error('Failed to parse plugin options:', options);
163 throw err;
164 }
165 }
166
167 plugins.push({ path: path, options: options, name: 'PlugIn_' + plugins.length });
168
169 break;
170 default:
171 files.push(arg);
172 }
173}
174
175if (build || watch) {
176 var file = files.shift();
177 try {
178 var stat = fs.statSync(file);
179
180 if (stat.isFile()) {
181 lumbarFile = file;
182
183 file = files.shift();
184 if (file) {
185 outputDir = file;
186 }
187 } else {
188 outputDir = file;
189 }
190 } catch (err) {
191 outputDir = file;
192 }
193
194 if (files.length) {
195 console.error(LONG_USAGE);
196 process.exit(3);
197 return true;
198 }
199} else {
200 console.error(LONG_USAGE);
201 process.exit(2);
202}
203
204plugins = plugins.map(function(plugin) {
205 var path = plugin.path;
206 var name = plugin.name;
207 var options = plugin.options;
208 try {
209 var fn = require(path);
210 } catch (err) {
211 try {
212 // Load from the current directory if not found in the normal lookup paths
213 fn = require(process.cwd() + '/node_modules/' + path);
214 } catch (err) {
215 // Last case, attempt to load from the plugins dir
216 fn = require('../lib/plugins/' + path);
217 }
218 }
219
220 lumbar.plugin(name, 'function' != typeof fn ? fn : fn(options));
221 return name;
222});
223
224var options = {
225 verbose: verbose,
226
227 libraries: libraries,
228 packageConfigFile: configFile,
229 minimize: minimize,
230 sourceMap: sourceMap,
231 outdir: outputDir,
232 plugins: plugins
233};
234
235// invoke init() from ../lib/lumbar.js.
236var arise = lumbar.init(lumbarFile, options),
237 // is worker going to point to watch or build func?
238 worker = watch ? arise.watch : arise.build,
239 lastMessage,
240 watchOutput = {},
241 growlList = [],
242 osType = require('os').type();
243
244function safeGrowl(msg, options) {
245 if (require('os').type().toLowerCase().match(/^windows/)) {
246 return;
247 }
248 try {
249 growl(msg, options);
250 } catch (err) {
251 if (err.errno === 'EMFILE') {
252 _.defer(safeGrowl, msg, options);
253 } else {
254 throw err;
255 }
256 }
257}
258
259var pingGrowl = _.debounce(function() {
260 safeGrowl('compiled: ' + growlList.map(function(file) { return file.substring(options.outdir.length); }).join('\n\t'), {title: 'Lumbar'});
261 growlList = [];
262}, 1000);
263
264arise.on('watch-change', function(status) {
265 if (!watchOutput[status.fileName]) {
266 console.log('\t\033[90mchanged\033[0m ' + status.fileName);
267 watchOutput[status.fileName] = true;
268 }
269});
270arise.on('log', function(log) {
271 if (verbose) {
272 console.log(log);
273 }
274});
275arise.on('output', function(status) {
276 if (status.error) {
277 return;
278 }
279
280 watchOutput = {};
281 if (status.watch) {
282 console.log('\033[90mwatching\033[0m ' + status.fileName);
283 } else {
284 console.log('\033[90mcompiled\033[0m ' + status.fileName);
285 }
286 if (status.warnings && status.warnings.length) {
287 if (watch) {
288 safeGrowl(status.warnings.length + ' warnings in ' + status.fileName, { title: 'Lumbar warnings', sticky: true });
289 }
290 console.log('\t\033[91m' + status.warnings.length + ' warnings\033[0m');
291 _.each(status.warnings, function(warning) {
292 console.log('\t\033[91mwarning\033[0m ' + warning.msg);
293 console.log('\t\tat ' + warning.file + ':' + warning.line + (warning.column ? ',' + warning.column : ''));
294 _.each(warning.context, function(line) {
295 console.log('\t' + line);
296 });
297 console.log();
298 });
299 }
300
301 if (watch) {
302 growlList.push(status.fileName);
303 pingGrowl();
304 }
305});
306arise.on('error', function(err) {
307 if ((err.source || err).code === 'EMFILE') {
308 throw err.source || err;
309 }
310
311 var message = err.stack || err.message;
312 if (lastMessage !== message) {
313 lastMessage = message;
314
315 console.error(message);
316 try {
317 safeGrowl(err.message, { title: 'Lumbar error', sticky: true });
318 } catch (err) {
319 console.log(err);
320 throw err;
321 }
322 }
323});
324
325// execute either watch() or build() and pass lumbar as the context.
326worker.call(arise, packageName, modules, function(err, status) {
327 if (err) {
328 throw err;
329 }
330});