1 | 'use strict';
|
2 |
|
3 | var fs = require('fs')
|
4 | , path = require('path')
|
5 | , readdirp = require('readdirp')
|
6 | , utl = require('./utl')
|
7 | , log = require('./log')
|
8 | , watchers = {}
|
9 | , watchedDirs = {}
|
10 | ;
|
11 |
|
12 | function dateEqual(d1, d2) {
|
13 | return d1.toGMTString() === d2.toGMTString();
|
14 | }
|
15 |
|
16 | function watchFile(entry, eventName, startedWatching, update) {
|
17 | var fullPath = entry.fullPath;
|
18 |
|
19 | if (watchers[fullPath]) return;
|
20 | startedWatching(entry);
|
21 |
|
22 | fs.watch(fullPath, { persistent: false }, function (event) {
|
23 | if (event !== eventName) return;
|
24 |
|
25 | var prevStat = watchers[fullPath].stat
|
26 | , entry = watchers[fullPath].entry
|
27 |
|
28 | fs.stat(fullPath, function (err, stat) {
|
29 | if (err) return log.error('watcher', err);
|
30 |
|
31 |
|
32 | if ( prevStat
|
33 | && dateEqual(prevStat.mtime, stat.mtime)
|
34 | && dateEqual(prevStat.ctime, stat.ctime)) return;
|
35 |
|
36 | watchers[fullPath].stat = stat
|
37 | update(entry);
|
38 | });
|
39 | });
|
40 | }
|
41 |
|
42 | function watchTree(options, addedWatch, update, watching) {
|
43 |
|
44 | function startedWatching(entry) {
|
45 | watchers[entry.fullPath] = { lastChange: new Date(), entry: entry };
|
46 | addedWatch({ entry: entry, all: watchers });
|
47 | }
|
48 |
|
49 | function watchDir(fullPath) {
|
50 | if (watchedDirs[fullPath]) return;
|
51 | watchedDirs[fullPath] = true;
|
52 |
|
53 | fs.watch(fullPath, { persistent: false }, function (event) {
|
54 | if (event !== 'rename') return;
|
55 | var cloned = utl.shallowClone(options);
|
56 |
|
57 | cloned.depth = 0;
|
58 | cloned.root = fullPath;
|
59 |
|
60 | readdirp(cloned)
|
61 | .on('warn', log.error)
|
62 | .on('error', log.error)
|
63 | .on('data', function (entry) {
|
64 | try {
|
65 | watchFile(entry, 'change', startedWatching, update);
|
66 | } catch(e) {
|
67 | log.error('Not watching: ' + entry.path);
|
68 | }
|
69 | });
|
70 | });
|
71 | }
|
72 |
|
73 | readdirp(options)
|
74 | .on('warn', log.error)
|
75 | .on('error', log.error)
|
76 | .on('data', function (entry) {
|
77 | try {
|
78 | watchFile(entry, 'change', startedWatching, update);
|
79 | watchDir(entry.fullParentDir, utl.shallowClone(options), watching, update);
|
80 | } catch(e) {
|
81 | log.error('Not watching: ' + entry.path);
|
82 | }
|
83 | })
|
84 | .on('end', function () {
|
85 | watchDir(options.root, utl.shallowClone(options), watching, update);
|
86 | if (watching) watching(watchers);
|
87 | });
|
88 | }
|
89 |
|
90 | module.exports = {
|
91 | watchFile: watchFile
|
92 | , watchTree: watchTree
|
93 | };
|