source: Dev/trunk/node_modules/grunt-contrib-watch/tasks/watch.js

Last change on this file was 533, checked in by hendrikvanantwerpen, 10 years ago

Add watch command to ease client development.

File size: 5.2 KB
Line 
1/*
2 * grunt-contrib-watch
3 * http://gruntjs.com/
4 *
5 * Copyright (c) 2014 "Cowboy" Ben Alman, contributors
6 * Licensed under the MIT license.
7 */
8
9var path = require('path');
10var Gaze = require('gaze').Gaze;
11var _ = require('lodash');
12var waiting = 'Waiting...';
13var changedFiles = Object.create(null);
14var watchers = [];
15
16module.exports = function(grunt) {
17  'use strict';
18
19  var taskrun = require('./lib/taskrunner')(grunt);
20
21  // Default date format logged
22  var dateFormat = function(time) {
23    grunt.log.writeln(String(
24      'Completed in ' +
25      time.toFixed(3) +
26      's at ' +
27      (new Date()).toString()
28    ).cyan + ' - ' + waiting);
29  };
30
31  // When task runner has started
32  taskrun.on('start', function() {
33    Object.keys(changedFiles).forEach(function(filepath) {
34      // Log which file has changed, and how.
35      grunt.log.ok('File "' + filepath + '" ' + changedFiles[filepath] + '.');
36    });
37    // Reset changedFiles
38    changedFiles = Object.create(null);
39  });
40
41  // When task runner has ended
42  taskrun.on('end', function(time) {
43    if (time > 0) {
44      dateFormat(time);
45    }
46  });
47
48  // When a task run has been interrupted
49  taskrun.on('interrupt', function() {
50    grunt.log.writeln('').write('Scheduled tasks have been interrupted...'.yellow);
51  });
52
53  // When taskrun is reloaded
54  taskrun.on('reload', function() {
55    taskrun.clearRequireCache(Object.keys(changedFiles));
56    grunt.log.writeln('').writeln('Reloading watch config...'.cyan);
57  });
58
59  grunt.registerTask('watch', 'Run predefined tasks whenever watched files change.', function(target) {
60    var self = this;
61    var name = self.name || 'watch';
62
63    // Close any previously opened watchers
64    watchers.forEach(function(watcher) {
65      watcher.close();
66    });
67    watchers = [];
68
69    // Never gonna give you up, never gonna let you down
70    if (grunt.config([name, 'options', 'forever']) !== false) {
71      taskrun.forever();
72    }
73
74    // If a custom dateFormat function
75    var df = grunt.config([name, 'options', 'dateFormat']);
76    if (typeof df === 'function') {
77      dateFormat = df;
78    }
79
80    if (taskrun.running === false) { grunt.log.writeln(waiting); }
81
82    // initialize taskrun
83    var targets = taskrun.init(name, {target: target});
84
85    targets.forEach(function(target, i) {
86      if (typeof target.files === 'string') { target.files = [target.files]; }
87
88      // Process into raw patterns
89      var patterns = _.chain(target.files).flatten().map(function(pattern) {
90        return grunt.config.process(pattern);
91      }).value();
92
93      // Validate the event option
94      if (typeof target.options.event === 'string') {
95        target.options.event = [target.options.event];
96      }
97
98      // Set cwd if options.cwd.file is set
99      if (typeof target.options.cwd !== 'string' && target.options.cwd.files) {
100        target.options.cwd = target.options.cwd.files;
101      }
102
103      // Create watcher per target
104      watchers.push(new Gaze(patterns, target.options, function(err) {
105        if (err) {
106          if (typeof err === 'string') { err = new Error(err); }
107          grunt.log.writeln('ERROR'.red);
108          grunt.fatal(err);
109          return taskrun.done();
110        }
111
112        // Log all watched files with --verbose set
113        if (grunt.option('verbose')) {
114          var watched = this.watched();
115          Object.keys(watched).forEach(function(watchedDir) {
116            watched[watchedDir].forEach(function(watchedFile) {
117              grunt.log.writeln('Watching ' + path.relative(process.cwd(), watchedFile) + ' for changes.');
118            });
119          });
120        }
121
122        // On changed/added/deleted
123        this.on('all', function(status, filepath) {
124
125          // Skip events not specified
126          if (!_.contains(target.options.event, 'all') &&
127              !_.contains(target.options.event, status)) {
128            return;
129          }
130
131          filepath = path.relative(process.cwd(), filepath);
132
133          // Skip empty filepaths
134          if (filepath === '') {
135            return;
136          }
137
138          // If Gruntfile.js changed, reload self task
139          if (target.options.reload || /gruntfile\.(js|coffee)/i.test(filepath)) {
140            taskrun.reload = true;
141          }
142
143          // Emit watch events if anyone is listening
144          if (grunt.event.listeners('watch').length > 0) {
145            grunt.event.emit('watch', status, filepath, target.name);
146          }
147
148          // Group changed files only for display
149          changedFiles[filepath] = status;
150
151          // Add changed files to the target
152          if (taskrun.targets[target.name]) {
153            if (!taskrun.targets[target.name].changedFiles) {
154              taskrun.targets[target.name].changedFiles = Object.create(null);
155            }
156            taskrun.targets[target.name].changedFiles[filepath] = status;
157          }
158
159          // Queue the target
160          if (taskrun.queue.indexOf(target.name) === -1) {
161            taskrun.queue.push(target.name);
162          }
163
164          // Run the tasks
165          taskrun.run();
166        });
167
168        // On watcher error
169        this.on('error', function(err) {
170          if (typeof err === 'string') { err = new Error(err); }
171          grunt.log.error(err.message);
172        });
173      }));
174    });
175
176  });
177};
Note: See TracBrowser for help on using the repository browser.