grunt-contrib-watch icon indicating copy to clipboard operation
grunt-contrib-watch copied to clipboard

New files in empty folder not watched

Open markgoodyear opened this issue 12 years ago • 118 comments

Hi,

I'm trying to set up watching Sass files and compiling them. Everything works great appart from when creating a new empty directory (or using an existing one which empty), then adding in a new file. Using grunt watch --verbose shows that the folder gets added, but any new files inside aren't recognised. If the folder already has a file inside, new files are recognised.

Is this a known issue?

A stripped down version of my Gruntfile.js for the two tasks involved is:

module.exports = function(grunt) {

  // Initialize Grunt
  grunt.initConfig({

    // Read package.json
    pkg: grunt.file.readJSON('package.json'),

    // Project meta
    meta: {

      // Filepaths
      dir: {
        js: 'js',
        css: 'css',
        sass: 'css/sass',
        img: 'img'
      }
    },

    // Sass
    sass: {
      dist: {
        options: {
          style: 'expanded'
        },
        files: {
          '<%= meta.dir.css %>/main.css': '<%= meta.dir.sass %>/main.scss'
        }
      }
    },

    // Watch
    watch: {
      sass: {
        files: '<%= meta.dir.sass %>/**/*',
        tasks: ['sass'],
      },
    }
  });

  // Load
  grunt.loadNpmTasks('grunt-contrib-sass');
  grunt.loadNpmTasks('grunt-contrib-watch');

  // Default task
  grunt.registerTask('default', ['sass']);

};

EDIT Just thought I should mention I'm running version 0.5.1.

markgoodyear avatar Jul 21 '13 20:07 markgoodyear

This issue should be fixed in >=0.5.0. Could you try npm cache clean && rm -rf node_modules/grunt-contrib-watch && npm install grunt-contrib-watch to ensure it's grabbing the latest version of gaze? Thanks!

shama avatar Jul 21 '13 21:07 shama

Hey @shama, I just tried that and it's still doing the same unfortunately, it did show that gaze is 0.4.1.

Is there anything else I could try, or anything that could help find the issue?

Cheers!

markgoodyear avatar Jul 21 '13 22:07 markgoodyear

Hmm which version of node.js and which os?

shama avatar Jul 22 '13 00:07 shama

I'm running:

  • Node v0.10.13
  • npm 1.3.4
  • grunt-cli v0.1.9
  • grunt v0.4.1
  • Mac OSX 10.8.4

markgoodyear avatar Jul 22 '13 07:07 markgoodyear

Same here. As far as I can see at least one file following the pattern in files must exist to trigger the watch event. So if target files is something like src/**/*.scss, adding a new .scss file to:

  • Empty dir doesn't work
  • dir with file dir/empty doesn't work
  • dir with file dir/file.scss works

I already updated to latest grunt-contrib-watch. Node v0.10.12 & Mac OSX 10.8.4.

luissquall avatar Jul 23 '13 17:07 luissquall

I can confirm what @luissquall describes is exact behavior I'm seeing.

markgoodyear avatar Jul 23 '13 18:07 markgoodyear

Just wondering if anyone's had chance to have a look at this? Would be awesome to automatically watch new files in empty folders.

@shama — If theres anything I can do to that could help find the issue just let me know.

markgoodyear avatar Jul 29 '13 14:07 markgoodyear

+1, I can confirm the same behavior as described by @luissquall

  • Node v0.10.15
  • npm 1.3.5
  • grunt 0.4.1
  • grunt-contrib-watch 0.5.1 (gaze 0.4.1)
  • Mac OSX 10.8.4

mnoble01 avatar Aug 07 '13 18:08 mnoble01

Thanks everyone! I'll take a look when I get a chance. I have tests for this in gaze so I'm not sure why it isn't working here. We should add a test case for it here and work backwards to figure out why.

shama avatar Aug 07 '13 18:08 shama

Update: the dir/empty case also occurs when dir doesn't have any files, but may contain folders

mnoble01 avatar Aug 07 '13 18:08 mnoble01

Any progress made on this one? I'm having the same issue on osx 10.8.4.

brett-shwom avatar Aug 16 '13 21:08 brett-shwom

I looked into it briefly, no real progress yet. Will look into more soon.

shama avatar Aug 16 '13 21:08 shama

@shama — If you need anything testing to help fix it I can try help out.

markgoodyear avatar Aug 16 '13 21:08 markgoodyear

In gaze.js, how about replacing:

    // If file was added
    current.filter(function(file) {
      return previous.indexOf(file) < 0;
    }).forEach(function(file) {
      // Is it a matching pattern?
      var relFile = path.join(relDir, file);
      // Add to watch then emit event
      self._internalAdd(relFile, function() {
        self.emit('added', path.join(dir, file));
      });
    });

with

    // If file was added
    current.filter(function(file) {
      return previous.indexOf(file) < 0;
    }).forEach(function(file) {
      // Is it a matching pattern?
      var relFile = path.join(relDir, file);
      var absFile = fs.realpathSync(relFile); //ADDED
      // Add to watch then emit event
        self._internalAdd(absFile, function() { //MODIFIED
        self.emit('added', path.join(dir, file));
      });
    });

?

minimatch.match doesn't seem to be able to handle relative paths. I can submit this as a pull request if it makes sense.

brett-shwom avatar Aug 17 '13 13:08 brett-shwom

I tried the above code change against the gaze project's tests. The following tests failed:

watchTest.js::addedEmitInSubFolders() matchingTest.js::addedLater()

ideas?

Environment: OSX 10.8.4 Node 0.10.15 Gaze 0.4.1 Grunt 0.4.1 npm 1.3.5

brett-shwom avatar Aug 17 '13 19:08 brett-shwom

How I usually go about these things is to write a new test case that matches the desired behavior. Then adjust the code until the new test passes along with the existing tests. This way we're sure we're working towards the fix we want without breaking any previous fixes made.

shama avatar Aug 17 '13 21:08 shama

I can jive with that. In the meantime, would you have any idea why those 2 particular test cases would be failing with the above code change?

brett-shwom avatar Aug 17 '13 22:08 brett-shwom

Okay, I figured out what's causing my issue. I was doing the following:

gaze('/Users/brett/Desktop/gazetestfolder/**/*', function(err, watcher) { ... })

i.e. I was using an absolute path instead of a relative path. The above invocation would result in newly created files in /gazetestfolder not registered.

If I use a relative path: gaze('../gazetestfolder/**/*', function(err, watcher) { ... }), then the new file additions to /gazetestfolder are registered.

Is this the intended behavior of gaze?

NB: my case is different than the case that @markgoodyear reported. I tried out his case (making a new directory then adding a file to it) and I do observe the same behavior that he has observed (new files added to that directory are not registered).

Maybe I should open up a separate issue for the absolute path stuff?

brett-shwom avatar Aug 18 '13 02:08 brett-shwom

Yes. There is an open issue for that here: shama/gaze#41 But it is low priority for me though as you can set the cwd option if you really need to pass absolute paths now.

shama avatar Aug 18 '13 02:08 shama

@markgoodyear @luissquall @mnoble01 Out of curiosity, are you using absolute paths as well?

shama avatar Aug 18 '13 03:08 shama

Hey @shama,

I've not had chance to test the above, however I do use relative paths in my Gruntfile, if that's what you're meaning?

I'll be able to check what @brett-shwom suggested later today (https://github.com/gruntjs/grunt-contrib-watch/issues/166#issuecomment-22811876).

Cheers

markgoodyear avatar Aug 18 '13 10:08 markgoodyear

@markgoodyear, I don't think that my suggestion will work for you. When I added that suggestion, I was under the impression that you and I were having the same issue. It turns out that I conflated our issues: I was using absolute paths and so no file creation events were getting triggered, whereas your issue was that file creation events weren't getting triggered when files were created in a folder that was created after the grunt watch task was kicked off. The code change I suggested only seems to add support file creation events that do not occur in new folders when an absolute path is specified in gaze().

brett-shwom avatar Aug 18 '13 12:08 brett-shwom

@shama, I'm also using relative paths in my Gruntfile...

mnoble01 avatar Aug 18 '13 15:08 mnoble01

+1 I'm also running into this issue with new files not being detected (although I hadn't linked it to empty directories)

herebefrogs avatar Aug 28 '13 15:08 herebefrogs

+1 .. same issue with latest libraries

pkieltyka avatar Sep 26 '13 14:09 pkieltyka

@pkieltyka what issue are you having?

brett-shwom avatar Sep 28 '13 17:09 brett-shwom

@brett-shwom I'm still having the same issue as my original post. New files in empty folders do not get picked up when using grunt watch. New folders work, just not a new file in an empty folder.

markgoodyear avatar Sep 28 '13 17:09 markgoodyear

Yea exactly.. I can see watch sees the new folder, but it should then watch the files in that directory as well.. if they match the glob pattern..

On 2013-09-28, at 1:18 PM, Mark Goodyear [email protected] wrote:

@brett-shwom I'm still having the same issue as my original post. New files in empty folders do not get picked up when using grunt watch. New folders work, just not a new file in an empty folder.

— Reply to this email directly or view it on GitHub.

pkieltyka avatar Sep 28 '13 17:09 pkieltyka

@brett-shwom thanks for the PR.. did you test it out btw? .. I did some debugging as well.. and one thing that came to mind is that perhaps it's actually a file glob matching issue.

For example, in my Gruntfile I have:

watch: {
  coffee: {
    files: ['src/**/*.coffee'],
    tasks: ['coffee:build']
  }
}

.. pretty standard. Now, if I create a new directory under src/, I can see the message ">> File 'src/x' added." where "x" is the new empty directory. That is followed by Grunt running my "coffee:build" task.. however, it shouldn't actually run that task because that doesn't match the pattern of *.coffee ... this is a definite problem in the pattern matching that is probably throwing things off as well.

I think it should actually do nothing when a new directory is added, other then perhaps add it to the list of directories to watch because of the ** match, and once it see's a .coffee file that matches the full pattern, then run the associated tasks.


Btw, I found another bug while I was fiddling around. When deleting an entire subfolder that contains watched files, the "watch" task completely misses that the folder and its files were deleted and doesn't even send the "deleted" target to grunt.event.on("watch",..). But, if you delete each watched file in a subfolder individually, it will send the "deleted" event for each file properly, as well execute the associated tasks.

pkieltyka avatar Sep 28 '13 23:09 pkieltyka

@pkieltyka Hey man,

Yeah, I did test it.

In addition to modifying the mkdirThenAddFile nodeunit test (part of the https://github.com/shama/gaze repo), I also created a sample script that listens to a events on a folder named /test. I ran the sample script, then created a folder, then created a .js file within that folder, and finally observed that a file added event was triggered.

If you want to give that sample script a shot,

  1. git clone [email protected]:brett-shwom/gaze.git
  2. git checkout track-file-additions-in-newly-created-folders
  3. npm install
  4. place the below code in [your-file-name].js
  5. ensure that the line require('../lib/gaze') is pointing to the gaze script in my branch
  6. mkdir [wherever you want]/test
  7. ensure that the line gaze('test/**/*.js', is pointing to [wherever you want]/test
  8. node [your-file-name].js
  9. mkdir [wherever you want]/test/a
  10. touch [wherever you want]/test/a/r.js
  11. observe [wherever you want]/test/a/r.js was added
var gaze = require('../lib/gaze'); 

// Watch all .js files/dirs in process.cwd()
gaze('test/**/*.js', function(err, watcher) {
  // Files have all started watching
  // watcher === this

  // Get all watched files
  console.log(this.watched());

  // On file changed
  this.on('changed', function(filepath) {
    console.log(filepath + ' was changed');
  });

  // On file added
  this.on('added', function(filepath) {
    console.log(filepath + ' was added');
  });

  // On file deleted
  this.on('deleted', function(filepath) {
    console.log(filepath + ' was deleted');
  });

  // Get watched files with relative paths
  console.log(this.relative());
});

brett-shwom avatar Sep 28 '13 23:09 brett-shwom