UNPKG

5.53 kBJavaScriptView Raw
1'use strict';
2
3// Nodejs libs.
4var path = require('path');
5
6// This allows grunt to require() .coffee files.
7try {
8 // Note: grunt no longer depends on CoffeeScript, it will only use it if it is intentionally
9 // installed in the project.
10 require('coffeescript/register');
11} catch (e) {
12 // This is fine, and will cause no problems so long as the user doesn't load .coffee files.
13 // Print a useful error if we attempt to load a .coffee file.
14 if (require.extensions) {
15 var FILE_EXTENSIONS = ['.coffee', '.litcoffee', '.coffee.md'];
16 for (var i = 0; i < FILE_EXTENSIONS.length; i++) {
17 require.extensions[FILE_EXTENSIONS[i]] = function() {
18 throw new Error(
19 'Grunt attempted to load a .coffee file but CoffeeScript was not installed.\n' +
20 'Please run `npm install --dev coffeescript` to enable loading CoffeeScript.'
21 );
22 };
23 }
24 }
25}
26
27// The module to be exported.
28var grunt = module.exports = {};
29
30// Expose internal grunt libs.
31function gRequire(name) {
32 return grunt[name] = require('./grunt/' + name);
33}
34
35var util = require('grunt-legacy-util');
36grunt.util = util;
37grunt.util.task = require('./util/task');
38
39var Log = require('grunt-legacy-log').Log;
40var log = new Log({grunt: grunt});
41grunt.log = log;
42
43gRequire('template');
44gRequire('event');
45var fail = gRequire('fail');
46gRequire('file');
47var option = gRequire('option');
48var config = gRequire('config');
49var task = gRequire('task');
50var help = gRequire('help');
51gRequire('cli');
52var verbose = grunt.verbose = log.verbose;
53
54// Expose some grunt metadata.
55grunt.package = require('../package.json');
56grunt.version = grunt.package.version;
57
58// Expose specific grunt lib methods on grunt.
59function gExpose(obj, methodName, newMethodName) {
60 grunt[newMethodName || methodName] = obj[methodName].bind(obj);
61}
62gExpose(task, 'registerTask');
63gExpose(task, 'registerMultiTask');
64gExpose(task, 'registerInitTask');
65gExpose(task, 'renameTask');
66gExpose(task, 'loadTasks');
67gExpose(task, 'loadNpmTasks');
68gExpose(config, 'init', 'initConfig');
69gExpose(fail, 'warn');
70gExpose(fail, 'fatal');
71
72// Expose the task interface. I've never called this manually, and have no idea
73// how it will work. But it might.
74grunt.tasks = function(tasks, options, done) {
75 // Update options with passed-in options.
76 option.init(options);
77
78 // Display the grunt version and quit if the user did --version.
79 var _tasks, _options;
80 if (option('version')) {
81 // Not --verbose.
82 log.writeln('grunt v' + grunt.version);
83
84 if (option('verbose')) {
85 // --verbose
86 verbose.writeln('Install path: ' + path.resolve(__dirname, '..'));
87 // Yes, this is a total hack, but we don't want to log all that verbose
88 // task initialization stuff here.
89 grunt.log.muted = true;
90 // Initialize task system so that available tasks can be listed.
91 grunt.task.init([], {help: true});
92 // Re-enable logging.
93 grunt.log.muted = false;
94
95 // Display available tasks (for shell completion, etc).
96 _tasks = Object.keys(grunt.task._tasks).sort();
97 verbose.writeln('Available tasks: ' + _tasks.join(' '));
98
99 // Display available options (for shell completion, etc).
100 _options = [];
101 Object.keys(grunt.cli.optlist).forEach(function(long) {
102 var o = grunt.cli.optlist[long];
103 _options.push('--' + (o.negate ? 'no-' : '') + long);
104 if (o.short) { _options.push('-' + o.short); }
105 });
106 verbose.writeln('Available options: ' + _options.join(' '));
107 }
108
109 return;
110 }
111
112 // Init colors.
113 log.initColors();
114
115 // Display help and quit if the user did --help.
116 if (option('help')) {
117 help.display();
118 return;
119 }
120
121 // A little header stuff.
122 verbose.header('Initializing').writeflags(option.flags(), 'Command-line options');
123
124 // Determine and output which tasks will be run.
125 var tasksSpecified = tasks && tasks.length > 0;
126 tasks = task.parseArgs([tasksSpecified ? tasks : 'default']);
127
128 // Initialize tasks.
129 task.init(tasks, options);
130
131 verbose.writeln();
132 if (!tasksSpecified) {
133 verbose.writeln('No tasks specified, running default tasks.');
134 }
135 verbose.writeflags(tasks, 'Running tasks');
136
137 // Handle otherwise unhandleable (probably asynchronous) exceptions.
138 var uncaughtHandler = function(e) {
139 fail.fatal(e, fail.code.TASK_FAILURE);
140 };
141 process.on('uncaughtException', uncaughtHandler);
142
143 // Report, etc when all tasks have completed.
144 task.options({
145 error: function(e) {
146 fail.warn(e, fail.code.TASK_FAILURE);
147 },
148 done: function() {
149 // Stop handling uncaught exceptions so that we don't leave any
150 // unwanted process-level side effects behind. There is no need to do
151 // this in the error callback, because fail.warn() will either kill
152 // the process, or with --force keep on going all the way here.
153 process.removeListener('uncaughtException', uncaughtHandler);
154
155 // Output a final fail / success report.
156 fail.report();
157
158 if (done) {
159 // Execute "done" function when done (only if passed, of course).
160 done();
161 } else {
162 // Otherwise, explicitly exit.
163 util.exit(0);
164 }
165 }
166 });
167
168 // Execute all tasks, in order. Passing each task individually in a forEach
169 // allows the error callback to execute multiple times.
170 tasks.forEach(function(name) { task.run(name); });
171 // Run tasks async internally to reduce call-stack, per:
172 // https://github.com/gruntjs/grunt/pull/1026
173 task.start({asyncDone: true});
174};