New files in empty folder not watched
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.
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!
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!
Hmm which version of node.js and which os?
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
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
dirdoesn't work -
dirwith filedir/emptydoesn't work -
dirwith filedir/file.scssworks
I already updated to latest grunt-contrib-watch. Node v0.10.12 & Mac OSX 10.8.4.
I can confirm what @luissquall describes is exact behavior I'm seeing.
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.
+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(gaze0.4.1) - Mac OSX
10.8.4
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.
Update: the dir/empty case also occurs when dir doesn't have any files, but may contain folders
Any progress made on this one? I'm having the same issue on osx 10.8.4.
I looked into it briefly, no real progress yet. Will look into more soon.
@shama — If you need anything testing to help fix it I can try help out.
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.
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
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.
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?
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?
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.
@markgoodyear @luissquall @mnoble01 Out of curiosity, are you using absolute paths as well?
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, 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().
@shama, I'm also using relative paths in my Gruntfile...
+1 I'm also running into this issue with new files not being detected (although I hadn't linked it to empty directories)
+1 .. same issue with latest libraries
@pkieltyka what issue are you having?
@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.
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.
@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 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,
-
git clone [email protected]:brett-shwom/gaze.git -
git checkout track-file-additions-in-newly-created-folders -
npm install - place the below code in [your-file-name].js
- ensure that the line
require('../lib/gaze')is pointing to the gaze script in my branch -
mkdir [wherever you want]/test - ensure that the line
gaze('test/**/*.js',is pointing to [wherever you want]/test -
node [your-file-name].js -
mkdir [wherever you want]/test/a -
touch [wherever you want]/test/a/r.js - 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());
});