You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

160 lines
4.7 KiB

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