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.

155 lines
4.5 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. taskrun.changedFiles = changedFiles;
  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. var beep = (!grunt.option('no-color')) ? '\x07' : '';
  31. grunt.log.writeln(beep).write(String(
  32. 'Completed in ' +
  33. time.toFixed(3) +
  34. 's at ' +
  35. (new Date()).toString()
  36. ).cyan + ' - ' + waiting);
  37. }
  38. });
  39. // When a task run has been interrupted
  40. taskrun.on('interrupt', function() {
  41. grunt.log.writeln('').write('Scheduled tasks have been interrupted...'.yellow);
  42. });
  43. // When taskrun is reloaded
  44. taskrun.on('reload', function() {
  45. taskrun.clearRequireCache(Object.keys(changedFiles));
  46. grunt.log.writeln('').writeln('Reloading watch config...'.cyan);
  47. });
  48. // On shutdown, close up watchers
  49. process.on('SIGINT', function() {
  50. grunt.log.writeln('').write('Shutting down the watch task...');
  51. watchers.forEach(function(watcher) {
  52. watcher.close();
  53. });
  54. grunt.log.ok();
  55. process.exit();
  56. });
  57. grunt.registerTask('watch', 'Run predefined tasks whenever watched files change.', function(target) {
  58. var self = this;
  59. var name = self.name || 'watch';
  60. // Never gonna give you up, never gonna let you down
  61. if (grunt.config([name, 'options', 'forever']) !== false) {
  62. taskrun.forever();
  63. }
  64. if (taskrun.running === false) { grunt.log.write(waiting); }
  65. // initialize taskrun
  66. var targets = taskrun.init(name, {
  67. interrupt: false,
  68. nospawn: false,
  69. event: ['all'],
  70. target: target,
  71. });
  72. targets.forEach(function(target, i) {
  73. if (typeof target.files === 'string') { target.files = [target.files]; }
  74. // Process into raw patterns
  75. var patterns = grunt.util._.chain(target.files).flatten().map(function(pattern) {
  76. return grunt.config.process(pattern);
  77. }).value();
  78. // Validate the event option
  79. if (typeof target.options.event === 'string') {
  80. target.options.event = [target.options.event];
  81. }
  82. // Create watcher per target
  83. watchers.push(new Gaze(patterns, target.options, function(err) {
  84. if (err) {
  85. if (typeof err === 'string') { err = new Error(err); }
  86. grunt.log.writeln('ERROR'.red);
  87. grunt.fatal(err);
  88. return taskrun.done();
  89. }
  90. // Log all watched files with --verbose set
  91. if (grunt.option('verbose')) {
  92. var watched = this.watched();
  93. Object.keys(watched).forEach(function(watchedDir) {
  94. watched[watchedDir].forEach(function(watchedFile) {
  95. grunt.log.writeln('Watching ' + path.relative(process.cwd(), watchedFile) + ' for changes.');
  96. });
  97. });
  98. }
  99. // On changed/added/deleted
  100. this.on('all', function(status, filepath) {
  101. // Skip events not specified
  102. if (!grunt.util._.contains(target.options.event, 'all') &&
  103. !grunt.util._.contains(target.options.event, status)) {
  104. return;
  105. }
  106. filepath = path.relative(process.cwd(), filepath);
  107. // If Gruntfile.js changed, reload self task
  108. if (/gruntfile\.(js|coffee)/i.test(filepath)) {
  109. taskrun.reload = true;
  110. }
  111. // Emit watch events if anyone is listening
  112. if (grunt.event.listeners('watch').length > 0) {
  113. grunt.event.emit('watch', status, filepath);
  114. }
  115. // Run tasks if any have been specified
  116. if (target.tasks) {
  117. changedFiles[filepath] = status;
  118. taskrun.queue(target.name);
  119. taskrun.run();
  120. }
  121. });
  122. // On watcher error
  123. this.on('error', function(err) {
  124. if (typeof err === 'string') { err = new Error(err); }
  125. grunt.log.error(err.message);
  126. });
  127. }));
  128. });
  129. });
  130. };