1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 | var grunt = require('../grunt');
|
11 |
|
12 |
|
13 | var path = require('path');
|
14 | var fs = require('fs');
|
15 |
|
16 |
|
17 | var parent = grunt.utils.task.create();
|
18 |
|
19 |
|
20 | var task = module.exports = Object.create(parent);
|
21 |
|
22 |
|
23 | var registry = {};
|
24 |
|
25 |
|
26 | var errorcount;
|
27 |
|
28 |
|
29 | task.registerTask = function(name, info, fn) {
|
30 |
|
31 | registry.tasks.push(name);
|
32 |
|
33 | parent.registerTask.apply(task, arguments);
|
34 |
|
35 | var thisTask = task._tasks[name];
|
36 |
|
37 | var _fn = thisTask.fn;
|
38 | thisTask.fn = function(arg) {
|
39 |
|
40 | errorcount = grunt.fail.errorcount;
|
41 |
|
42 | this.__defineGetter__('errorCount', function() {
|
43 | return grunt.fail.errorcount - errorcount;
|
44 | });
|
45 |
|
46 | this.requires = task.requires.bind(task);
|
47 |
|
48 | this.requiresConfig = grunt.config.requires;
|
49 |
|
50 |
|
51 | var logger = _fn.alias || (thisTask.multi && (!arg || arg === '*')) ? 'verbose' : 'log';
|
52 |
|
53 | grunt[logger].header('Running "' + this.nameArgs + '"' +
|
54 | (this.name !== this.nameArgs ? ' (' + this.name + ')' : '') + ' task');
|
55 |
|
56 | return _fn.apply(this, arguments);
|
57 | };
|
58 | return task;
|
59 | };
|
60 |
|
61 |
|
62 | task.registerMultiTask = function(name, info, fn) {
|
63 | task.registerTask(name, info, function(target) {
|
64 |
|
65 | if (!target || target === '*') {
|
66 | return task.runAllTargets(name, grunt.utils.toArray(arguments).slice(1));
|
67 | }
|
68 |
|
69 | this.requiresConfig([name, target]);
|
70 |
|
71 | this.data = grunt.config([name, target]);
|
72 |
|
73 | this.file = {};
|
74 |
|
75 |
|
76 |
|
77 | if (grunt.utils.kindOf(this.data) === 'object') {
|
78 | if ('src' in this.data) { this.file.src = this.data.src; }
|
79 | if ('dest' in this.data) { this.file.dest = this.data.dest; }
|
80 | } else {
|
81 | this.file.src = this.data;
|
82 | this.file.dest = target;
|
83 | }
|
84 |
|
85 | if (this.file.src) {
|
86 | this.file.src = grunt.utils.recurse(this.file.src, function(src) {
|
87 | if (typeof src !== 'string') { return src; }
|
88 | return grunt.template.process(src);
|
89 | });
|
90 | }
|
91 |
|
92 | if (this.file.dest) {
|
93 | this.file.dest = grunt.template.process(this.file.dest);
|
94 | }
|
95 |
|
96 | this.target = target;
|
97 |
|
98 | this.args = grunt.utils.toArray(arguments).slice(1);
|
99 |
|
100 | this.flags = {};
|
101 | this.args.forEach(function(arg) { this.flags[arg] = true; }, this);
|
102 |
|
103 | return fn.apply(this, this.args);
|
104 | });
|
105 | task._tasks[name].multi = true;
|
106 | };
|
107 |
|
108 |
|
109 |
|
110 | task.registerInitTask = function(name, info, fn) {
|
111 | task.registerTask(name, info, fn);
|
112 | task._tasks[name].init = true;
|
113 | };
|
114 |
|
115 |
|
116 | task.registerHelper = function(name, fn) {
|
117 |
|
118 | registry.helpers.push(name);
|
119 |
|
120 | return parent.registerHelper.apply(task, arguments);
|
121 | };
|
122 |
|
123 |
|
124 | task.runAllTargets = function(taskname, args) {
|
125 |
|
126 | var targets = Object.keys(grunt.config(taskname) || {});
|
127 |
|
128 | if (targets.length === 0) {
|
129 | grunt.log.error('No "' + taskname + '" targets found.');
|
130 | return false;
|
131 | }
|
132 |
|
133 | targets.filter(function(target) {
|
134 | return !/^_/.test(target);
|
135 | }).forEach(function(target) {
|
136 |
|
137 | task.run([taskname, target].concat(args || []).join(':'));
|
138 | });
|
139 | };
|
140 |
|
141 |
|
142 | var loadTaskStack = [];
|
143 | function loadTask(filepath) {
|
144 |
|
145 | loadTaskStack.push({tasks: registry.tasks, helpers: registry.helpers});
|
146 |
|
147 | registry.tasks = [];
|
148 | registry.helpers = [];
|
149 | var file = path.basename(filepath);
|
150 | var msg = 'Loading "' + file + '" tasks and helpers...';
|
151 | var fn;
|
152 | try {
|
153 |
|
154 | fn = require(path.resolve(filepath));
|
155 | if (typeof fn === 'function') {
|
156 | fn.call(grunt, grunt);
|
157 | }
|
158 | grunt.verbose.write(msg).ok();
|
159 | if (registry.tasks.length === 0 && registry.helpers.length === 0) {
|
160 | grunt.verbose.error('No new tasks or helpers found.');
|
161 | } else {
|
162 | if (registry.tasks.length > 0) {
|
163 | grunt.verbose.writeln('Tasks: ' + grunt.log.wordlist(registry.tasks));
|
164 | }
|
165 | if (registry.helpers.length > 0) {
|
166 | grunt.verbose.writeln('Helpers: ' + grunt.log.wordlist(registry.helpers));
|
167 | }
|
168 | }
|
169 | } catch(e) {
|
170 |
|
171 | grunt.log.write(msg).error().verbose.error(e.stack).or.error(e);
|
172 | }
|
173 |
|
174 | var obj = loadTaskStack.pop() || {};
|
175 | registry.tasks = obj.tasks || [];
|
176 | registry.helpers = obj.helpers || [];
|
177 | }
|
178 |
|
179 |
|
180 | function loadTasksMessage(info) {
|
181 | grunt.verbose.subhead('Registering ' + info + ' tasks.');
|
182 | }
|
183 |
|
184 |
|
185 | function loadTasks(tasksdir) {
|
186 | try {
|
187 | fs.readdirSync(tasksdir).filter(function(filename) {
|
188 |
|
189 | return path.extname(filename).toLowerCase() === '.js';
|
190 | }).forEach(function(filename) {
|
191 |
|
192 | loadTask(path.join(tasksdir, filename));
|
193 | });
|
194 | } catch(e) {
|
195 | grunt.log.verbose.error(e.stack).or.error(e);
|
196 | }
|
197 | }
|
198 |
|
199 |
|
200 | task.searchDirs = [];
|
201 |
|
202 |
|
203 |
|
204 |
|
205 |
|
206 | function expandByMethod(method) {
|
207 | var args = grunt.utils.toArray(arguments).slice(1);
|
208 |
|
209 | var options = grunt.utils.kindOf(args[0]) === 'object' ? args.shift() : {};
|
210 |
|
211 |
|
212 | var patterns = Array.isArray(args[0]) ? args[0] : args;
|
213 | var filepaths = {};
|
214 |
|
215 |
|
216 | var toString = function() { return this.abs; };
|
217 |
|
218 | task.searchDirs.forEach(function(dirpath) {
|
219 |
|
220 | var args = patterns.map(function(pattern) {
|
221 | return path.join(dirpath, pattern);
|
222 | });
|
223 |
|
224 | args.unshift(options);
|
225 |
|
226 | grunt.file[method].apply(null, args).forEach(function(abspath) {
|
227 | var relpath = abspath.slice(dirpath.length + 1);
|
228 | if (relpath in filepaths) { return; }
|
229 |
|
230 | filepaths[relpath] = {
|
231 | abs: abspath,
|
232 | rel: relpath,
|
233 | base: abspath.slice(0, dirpath.length),
|
234 | toString: toString
|
235 | };
|
236 | });
|
237 | });
|
238 |
|
239 | return Object.keys(filepaths).map(function(relpath) {
|
240 | return filepaths[relpath];
|
241 | });
|
242 | }
|
243 |
|
244 |
|
245 |
|
246 | task.expand = expandByMethod.bind(task, 'expand');
|
247 | task.expandDirs = expandByMethod.bind(task, 'expandDirs');
|
248 | task.expandFiles = expandByMethod.bind(task, 'expandFiles');
|
249 |
|
250 |
|
251 | task.getFile = function() {
|
252 | var filepath = path.join.apply(path, arguments);
|
253 | var fileobj = task.expand(filepath)[0];
|
254 | return fileobj ? String(fileobj) : null;
|
255 | };
|
256 |
|
257 |
|
258 |
|
259 | var readDefaults = {};
|
260 | task.readDefaults = function() {
|
261 | var filepath = path.join.apply(path, arguments);
|
262 | var result = readDefaults[filepath];
|
263 | var filepaths;
|
264 | if (!result) {
|
265 | result = readDefaults[filepath] = {};
|
266 |
|
267 | filepaths = task.searchDirs.map(function(dirpath) {
|
268 | return path.join(dirpath, filepath);
|
269 | }).filter(function(filepath) {
|
270 | return path.existsSync(filepath) && fs.statSync(filepath).isFile();
|
271 | });
|
272 |
|
273 | if (filepaths.length) {
|
274 | grunt.verbose.subhead('Loading data from ' + filepath);
|
275 |
|
276 |
|
277 | filepaths.forEach(function(filepath) {
|
278 | grunt.utils._.defaults(result, grunt.file.readJSON(filepath));
|
279 | });
|
280 | }
|
281 | }
|
282 | return result;
|
283 | };
|
284 |
|
285 |
|
286 | task.loadTasks = function(tasksdir) {
|
287 | loadTasksMessage('"' + tasksdir + '"');
|
288 | if (path.existsSync(tasksdir)) {
|
289 | task.searchDirs.unshift(tasksdir);
|
290 | loadTasks(tasksdir);
|
291 | } else {
|
292 | grunt.log.error('Tasks directory "' + tasksdir + '" not found.');
|
293 | }
|
294 | };
|
295 |
|
296 |
|
297 |
|
298 | task.loadNpmTasks = function(name) {
|
299 | loadTasksMessage('"' + name + '" local Npm module');
|
300 | var tasksdir = path.resolve('node_modules', name, 'tasks');
|
301 | if (path.existsSync(tasksdir)) {
|
302 | task.searchDirs.unshift(tasksdir);
|
303 | loadTasks(tasksdir);
|
304 | } else {
|
305 | grunt.log.error('Local Npm module "' + name + '" not found. Is it installed?');
|
306 | }
|
307 | };
|
308 |
|
309 |
|
310 |
|
311 | function loadNpmTasksWithRequire(name) {
|
312 | loadTasksMessage('"' + name + '" npm module');
|
313 | var dirpath;
|
314 | try {
|
315 | dirpath = require.resolve(name);
|
316 | dirpath = path.resolve(path.join(path.dirname(dirpath), 'tasks'));
|
317 | if (path.existsSync(dirpath)) {
|
318 | task.searchDirs.unshift(dirpath);
|
319 | loadTasks(dirpath);
|
320 | return;
|
321 | }
|
322 | } catch (e) {}
|
323 |
|
324 | grunt.log.error('Npm module "' + name + '" not found. Is it installed?');
|
325 | }
|
326 |
|
327 |
|
328 | task.init = function(tasks, options) {
|
329 | if (!options) { options = {}; }
|
330 |
|
331 |
|
332 | var tasksdir = path.resolve(__dirname, '../../tasks');
|
333 | task.searchDirs.unshift(tasksdir);
|
334 | loadTasksMessage('built-in');
|
335 | loadTasks(tasksdir);
|
336 |
|
337 |
|
338 |
|
339 | grunt._npmTasks.forEach(loadNpmTasksWithRequire);
|
340 |
|
341 |
|
342 | var allInit = tasks.length > 0 && tasks.every(function(name) {
|
343 | var obj = task._taskPlusArgs(name).task;
|
344 | return obj && obj.init;
|
345 | });
|
346 |
|
347 |
|
348 |
|
349 | var configfile = allInit ? null : grunt.option('config') ||
|
350 | grunt.file.findup(process.cwd(), 'grunt.js');
|
351 |
|
352 | var msg = 'Reading "' + path.basename(configfile) + '" config file...';
|
353 | if (configfile && path.existsSync(configfile)) {
|
354 | grunt.verbose.writeln().write(msg).ok();
|
355 |
|
356 |
|
357 | process.chdir(grunt.option('base') || path.dirname(configfile));
|
358 |
|
359 | loadTask(configfile);
|
360 | } else if (options.help || allInit) {
|
361 |
|
362 | } else if (grunt.option('config')) {
|
363 |
|
364 | grunt.log.writeln().write(msg).error();
|
365 | grunt.fatal('Unable to find "' + configfile + '" config file.', 2);
|
366 | } else if (!grunt.option('help')) {
|
367 | grunt.verbose.writeln().write(msg).error();
|
368 | grunt.fatal('Unable to find "grunt.js" config file. Do you need any --help?', 2);
|
369 | }
|
370 |
|
371 |
|
372 | (grunt.option('npm') || []).forEach(task.loadNpmTasks);
|
373 |
|
374 | (grunt.option('tasks') || []).forEach(task.loadTasks);
|
375 |
|
376 |
|
377 | tasksdir = grunt.file.userDir('tasks');
|
378 | if (tasksdir) {
|
379 | task.searchDirs.unshift(tasksdir);
|
380 | loadTasksMessage('user');
|
381 | loadTasks(tasksdir);
|
382 | }
|
383 |
|
384 |
|
385 | task.searchDirs = grunt.utils._.uniq(task.searchDirs).map(function(filepath) {
|
386 | return path.resolve(filepath);
|
387 | });
|
388 | };
|