Added logging, changed some directory structure

This commit is contained in:
2018-01-13 21:33:40 -05:00
parent f079a5f067
commit 8e72ffb917
73656 changed files with 35284 additions and 53718 deletions

View File

@@ -0,0 +1,20 @@
Copyright JS Foundation and other contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,72 @@
# watchpack
Wrapper library for directory and file watching.
[![Build Status](https://travis-ci.org/webpack/watchpack.svg?branch=master)](https://travis-ci.org/webpack/watchpack) [![Build status](https://ci.appveyor.com/api/projects/status/e5u2qvmugtv0r647/branch/master?svg=true)](https://ci.appveyor.com/project/sokra/watchpack/branch/master) [![Test coverage][coveralls-image]][coveralls-url]
## Concept
watchpack high level API don't map directly to watchers. Instead a three level architecture ensures that for each directory only a single watcher exists.
* The high level API requests `DirectoryWatchers` from a `WatcherManager`, which ensures that only a single `DirectoryWatcher` per directory is created.
* A user-faced `Watcher` can be obtained from a `DirectoryWatcher` and provides a filtered view on the `DirectoryWatcher`.
* Reference-counting is used on the `DirectoryWatcher` and `Watcher` to decide when to close them.
* The real watchers (currently chokidar) are created by the `DirectoryWatcher`.
* Files are never watched directly. This should keep the watcher count low.
* Watching can be started in the past. This way watching can start after file reading.
* Symlinks are not followed, instead the symlink is watched.
## API
``` javascript
var Watchpack = require("watchpack");
var wp = new Watchpack({
// options:
aggregateTimeout: 1000
// fire "aggregated" event when after a change for 1000ms no additonal change occured
// aggregated defaults to undefined, which doesn't fire an "aggregated" event
poll: true
// poll: true - use polling with the default interval
// poll: 10000 - use polling with an interval of 10s
// poll defaults to undefined, which prefer native watching methods
// Note: enable polling when watching on a network path
ignored: /node_modules/,
// anymatch-compatible definition of files/paths to be ignored
// see https://github.com/paulmillr/chokidar#path-filtering
});
// Watchpack.prototype.watch(string[] files, string[] directories, [number startTime])
wp.watch(listOfFiles, listOfDirectories, Date.now() - 10000);
// starts watching these files and directories
// calling this again will override the files and directories
wp.on("change", function(filePath, mtime) {
// filePath: the changed file
// mtime: last modified time for the changed file
});
wp.on("aggregated", function(changes) {
// changes: an array of all changed files
});
// Watchpack.prototype.pause()
wp.pause();
// stops emitting events, but keeps watchers open
// next "watch" call can reuse the watchers
// Watchpack.prototype.close()
wp.close();
// stops emitting events and closes all watchers
// Watchpack.prototype.getTimes()
var fileTimes = wp.getTimes();
// returns an object with all know change times for files
// this include timestamps from files not directly watched
// key: absolute path, value: timestamp as number
```
[coveralls-url]: https://coveralls.io/r/webpack/watchpack/
[coveralls-image]: https://img.shields.io/coveralls/webpack/watchpack.svg

View File

@@ -0,0 +1,356 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
var EventEmitter = require("events").EventEmitter;
var async = require("async");
var chokidar = require("chokidar");
var fs = require("graceful-fs");
var path = require("path");
var watcherManager = require("./watcherManager");
var FS_ACCURACY = 10000;
function withoutCase(str) {
return str.toLowerCase();
}
function Watcher(directoryWatcher, filePath, startTime) {
EventEmitter.call(this);
this.directoryWatcher = directoryWatcher;
this.path = filePath;
this.startTime = startTime && +startTime;
this.data = 0;
}
Watcher.prototype = Object.create(EventEmitter.prototype);
Watcher.prototype.constructor = Watcher;
Watcher.prototype.checkStartTime = function checkStartTime(mtime, initial) {
if(typeof this.startTime !== "number") return !initial;
var startTime = this.startTime;
return startTime <= mtime;
};
Watcher.prototype.close = function close() {
this.emit("closed");
};
function DirectoryWatcher(directoryPath, options) {
EventEmitter.call(this);
this.options = options;
this.path = directoryPath;
this.files = Object.create(null);
this.directories = Object.create(null);
this.watcher = chokidar.watch(directoryPath, {
ignoreInitial: true,
persistent: true,
followSymlinks: false,
depth: 0,
atomic: false,
alwaysStat: true,
ignorePermissionErrors: true,
ignored: options.ignored,
usePolling: options.poll ? true : undefined,
interval: typeof options.poll === "number" ? options.poll : undefined,
disableGlobbing: true
});
this.watcher.on("add", this.onFileAdded.bind(this));
this.watcher.on("addDir", this.onDirectoryAdded.bind(this));
this.watcher.on("change", this.onChange.bind(this));
this.watcher.on("unlink", this.onFileUnlinked.bind(this));
this.watcher.on("unlinkDir", this.onDirectoryUnlinked.bind(this));
this.watcher.on("error", this.onWatcherError.bind(this));
this.initialScan = true;
this.nestedWatching = false;
this.initialScanRemoved = [];
this.doInitialScan();
this.watchers = Object.create(null);
this.refs = 0;
}
module.exports = DirectoryWatcher;
DirectoryWatcher.prototype = Object.create(EventEmitter.prototype);
DirectoryWatcher.prototype.constructor = DirectoryWatcher;
DirectoryWatcher.prototype.setFileTime = function setFileTime(filePath, mtime, initial, type) {
var now = Date.now();
var old = this.files[filePath];
this.files[filePath] = [initial ? Math.min(now, mtime) : now, mtime];
// we add the fs accurency to reach the maximum possible mtime
if(mtime)
mtime = mtime + FS_ACCURACY;
if(!old) {
if(mtime) {
if(this.watchers[withoutCase(filePath)]) {
this.watchers[withoutCase(filePath)].forEach(function(w) {
if(!initial || w.checkStartTime(mtime, initial)) {
w.emit("change", mtime, initial ? "initial" : type);
}
});
}
}
} else if(!initial && mtime && type !== "add") {
if(this.watchers[withoutCase(filePath)]) {
this.watchers[withoutCase(filePath)].forEach(function(w) {
w.emit("change", mtime, type);
});
}
} else if(!initial && !mtime) {
if(this.watchers[withoutCase(filePath)]) {
this.watchers[withoutCase(filePath)].forEach(function(w) {
w.emit("remove", type);
});
}
}
if(this.watchers[withoutCase(this.path)]) {
this.watchers[withoutCase(this.path)].forEach(function(w) {
if(!initial || w.checkStartTime(mtime, initial)) {
w.emit("change", filePath, mtime, initial ? "initial" : type);
}
});
}
};
DirectoryWatcher.prototype.setDirectory = function setDirectory(directoryPath, exist, initial, type) {
if(directoryPath === this.path) {
if(!initial && this.watchers[withoutCase(this.path)]) {
this.watchers[withoutCase(this.path)].forEach(function(w) {
w.emit("change", directoryPath, w.data, initial ? "initial" : type);
});
}
} else {
var old = this.directories[directoryPath];
if(!old) {
if(exist) {
if(this.nestedWatching) {
this.createNestedWatcher(directoryPath);
} else {
this.directories[directoryPath] = true;
}
if(!initial && this.watchers[withoutCase(this.path)]) {
this.watchers[withoutCase(this.path)].forEach(function(w) {
w.emit("change", directoryPath, w.data, initial ? "initial" : type);
});
}
}
} else {
if(!exist) {
if(this.nestedWatching)
this.directories[directoryPath].close();
delete this.directories[directoryPath];
if(!initial && this.watchers[withoutCase(this.path)]) {
this.watchers[withoutCase(this.path)].forEach(function(w) {
w.emit("change", directoryPath, w.data, initial ? "initial" : type);
});
}
}
}
}
};
DirectoryWatcher.prototype.createNestedWatcher = function(directoryPath) {
this.directories[directoryPath] = watcherManager.watchDirectory(directoryPath, this.options, 1);
this.directories[directoryPath].on("change", function(filePath, mtime, type) {
if(this.watchers[withoutCase(this.path)]) {
this.watchers[withoutCase(this.path)].forEach(function(w) {
if(w.checkStartTime(mtime, false)) {
w.emit("change", filePath, mtime, type);
}
});
}
}.bind(this));
};
DirectoryWatcher.prototype.setNestedWatching = function(flag) {
if(this.nestedWatching !== !!flag) {
this.nestedWatching = !!flag;
if(this.nestedWatching) {
Object.keys(this.directories).forEach(function(directory) {
this.createNestedWatcher(directory);
}, this);
} else {
Object.keys(this.directories).forEach(function(directory) {
this.directories[directory].close();
this.directories[directory] = true;
}, this);
}
}
};
DirectoryWatcher.prototype.watch = function watch(filePath, startTime) {
this.watchers[withoutCase(filePath)] = this.watchers[withoutCase(filePath)] || [];
this.refs++;
var watcher = new Watcher(this, filePath, startTime);
watcher.on("closed", function() {
var idx = this.watchers[withoutCase(filePath)].indexOf(watcher);
this.watchers[withoutCase(filePath)].splice(idx, 1);
if(this.watchers[withoutCase(filePath)].length === 0) {
delete this.watchers[withoutCase(filePath)];
if(this.path === filePath)
this.setNestedWatching(false);
}
if(--this.refs <= 0)
this.close();
}.bind(this));
this.watchers[withoutCase(filePath)].push(watcher);
var data;
if(filePath === this.path) {
this.setNestedWatching(true);
data = false;
Object.keys(this.files).forEach(function(file) {
var d = this.files[file];
if(!data)
data = d;
else
data = [Math.max(data[0], d[0]), Math.max(data[1], d[1])];
}, this);
} else {
data = this.files[filePath];
}
process.nextTick(function() {
if(data) {
var ts = data[0] === data[1] ? data[0] + FS_ACCURACY : data[0];
if(ts >= startTime)
watcher.emit("change", data[1]);
} else if(this.initialScan && this.initialScanRemoved.indexOf(filePath) >= 0) {
watcher.emit("remove");
}
}.bind(this));
return watcher;
};
DirectoryWatcher.prototype.onFileAdded = function onFileAdded(filePath, stat) {
if(filePath.indexOf(this.path) !== 0) return;
if(/[\\\/]/.test(filePath.substr(this.path.length + 1))) return;
this.setFileTime(filePath, +stat.mtime, false, "add");
};
DirectoryWatcher.prototype.onDirectoryAdded = function onDirectoryAdded(directoryPath /*, stat */) {
if(directoryPath.indexOf(this.path) !== 0) return;
if(/[\\\/]/.test(directoryPath.substr(this.path.length + 1))) return;
this.setDirectory(directoryPath, true, false, "add");
};
DirectoryWatcher.prototype.onChange = function onChange(filePath, stat) {
if(filePath.indexOf(this.path) !== 0) return;
if(/[\\\/]/.test(filePath.substr(this.path.length + 1))) return;
var mtime = +stat.mtime;
ensureFsAccuracy(mtime);
this.setFileTime(filePath, mtime, false, "change");
};
DirectoryWatcher.prototype.onFileUnlinked = function onFileUnlinked(filePath) {
if(filePath.indexOf(this.path) !== 0) return;
if(/[\\\/]/.test(filePath.substr(this.path.length + 1))) return;
this.setFileTime(filePath, null, false, "unlink");
if(this.initialScan) {
this.initialScanRemoved.push(filePath);
}
};
DirectoryWatcher.prototype.onDirectoryUnlinked = function onDirectoryUnlinked(directoryPath) {
if(directoryPath.indexOf(this.path) !== 0) return;
if(/[\\\/]/.test(directoryPath.substr(this.path.length + 1))) return;
this.setDirectory(directoryPath, false, false, "unlink");
if(this.initialScan) {
this.initialScanRemoved.push(directoryPath);
}
};
DirectoryWatcher.prototype.onWatcherError = function onWatcherError(/* err */) {
};
DirectoryWatcher.prototype.doInitialScan = function doInitialScan() {
fs.readdir(this.path, function(err, items) {
if(err) {
this.initialScan = false;
return;
}
async.forEach(items, function(item, callback) {
var itemPath = path.join(this.path, item);
fs.stat(itemPath, function(err2, stat) {
if(!this.initialScan) return;
if(err2) {
callback();
return;
}
if(stat.isFile()) {
if(!this.files[itemPath])
this.setFileTime(itemPath, +stat.mtime, true);
} else if(stat.isDirectory()) {
if(!this.directories[itemPath])
this.setDirectory(itemPath, true, true);
}
callback();
}.bind(this));
}.bind(this), function() {
this.initialScan = false;
this.initialScanRemoved = null;
}.bind(this));
}.bind(this));
};
DirectoryWatcher.prototype.getTimes = function() {
var obj = Object.create(null);
var selfTime = 0;
Object.keys(this.files).forEach(function(file) {
var data = this.files[file];
var time;
if(data[1]) {
time = Math.max(data[0], data[1] + FS_ACCURACY);
} else {
time = data[0];
}
obj[file] = time;
if(time > selfTime)
selfTime = time;
}, this);
if(this.nestedWatching) {
Object.keys(this.directories).forEach(function(dir) {
var w = this.directories[dir];
var times = w.directoryWatcher.getTimes();
Object.keys(times).forEach(function(file) {
var time = times[file];
obj[file] = time;
if(time > selfTime)
selfTime = time;
});
}, this);
obj[this.path] = selfTime;
}
return obj;
};
DirectoryWatcher.prototype.close = function() {
this.initialScan = false;
this.watcher.close();
if(this.nestedWatching) {
Object.keys(this.directories).forEach(function(dir) {
this.directories[dir].close();
}, this);
}
this.emit("closed");
};
function ensureFsAccuracy(mtime) {
if(!mtime) return;
if(FS_ACCURACY > 1 && mtime % 1 !== 0)
FS_ACCURACY = 1;
else if(FS_ACCURACY > 10 && mtime % 10 !== 0)
FS_ACCURACY = 10;
else if(FS_ACCURACY > 100 && mtime % 100 !== 0)
FS_ACCURACY = 100;
else if(FS_ACCURACY > 1000 && mtime % 1000 !== 0)
FS_ACCURACY = 1000;
else if(FS_ACCURACY > 2000 && mtime % 2000 !== 0)
FS_ACCURACY = 2000;
}

View File

@@ -0,0 +1,33 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
var path = require("path");
function WatcherManager() {
this.directoryWatchers = {};
}
WatcherManager.prototype.getDirectoryWatcher = function(directory, options) {
var DirectoryWatcher = require("./DirectoryWatcher");
options = options || {};
var key = directory + " " + JSON.stringify(options);
if(!this.directoryWatchers[key]) {
this.directoryWatchers[key] = new DirectoryWatcher(directory, options);
this.directoryWatchers[key].on("closed", function() {
delete this.directoryWatchers[key];
}.bind(this));
}
return this.directoryWatchers[key];
};
WatcherManager.prototype.watchFile = function watchFile(p, options, startTime) {
var directory = path.dirname(p);
return this.getDirectoryWatcher(directory, options).watch(p, startTime);
};
WatcherManager.prototype.watchDirectory = function watchDirectory(directory, options, startTime) {
return this.getDirectoryWatcher(directory, options).watch(directory, startTime);
};
module.exports = new WatcherManager();

View File

@@ -0,0 +1,143 @@
/*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
var watcherManager = require("./watcherManager");
var EventEmitter = require("events").EventEmitter;
function Watchpack(options) {
EventEmitter.call(this);
if(!options) options = {};
if(!options.aggregateTimeout) options.aggregateTimeout = 200;
this.options = options;
this.watcherOptions = {
ignored: options.ignored,
poll: options.poll
};
this.fileWatchers = [];
this.dirWatchers = [];
this.mtimes = Object.create(null);
this.paused = false;
this.aggregatedChanges = [];
this.aggregatedRemovals = [];
this.aggregateTimeout = 0;
this._onTimeout = this._onTimeout.bind(this);
}
module.exports = Watchpack;
Watchpack.prototype = Object.create(EventEmitter.prototype);
Watchpack.prototype.watch = function watch(files, directories, startTime) {
this.paused = false;
var oldFileWatchers = this.fileWatchers;
var oldDirWatchers = this.dirWatchers;
this.fileWatchers = files.map(function(file) {
return this._fileWatcher(file, watcherManager.watchFile(file, this.watcherOptions, startTime));
}, this);
this.dirWatchers = directories.map(function(dir) {
return this._dirWatcher(dir, watcherManager.watchDirectory(dir, this.watcherOptions, startTime));
}, this);
oldFileWatchers.forEach(function(w) {
w.close();
}, this);
oldDirWatchers.forEach(function(w) {
w.close();
}, this);
};
Watchpack.prototype.close = function resume() {
this.paused = true;
if(this.aggregateTimeout)
clearTimeout(this.aggregateTimeout);
this.fileWatchers.forEach(function(w) {
w.close();
}, this);
this.dirWatchers.forEach(function(w) {
w.close();
}, this);
this.fileWatchers.length = 0;
this.dirWatchers.length = 0;
};
Watchpack.prototype.pause = function pause() {
this.paused = true;
if(this.aggregateTimeout)
clearTimeout(this.aggregateTimeout);
};
function addWatchersToArray(watchers, array) {
watchers.forEach(function(w) {
if(array.indexOf(w.directoryWatcher) < 0) {
array.push(w.directoryWatcher);
addWatchersToArray(Object.keys(w.directoryWatcher.directories).reduce(function(a, dir) {
if(w.directoryWatcher.directories[dir] !== true)
a.push(w.directoryWatcher.directories[dir]);
return a;
}, []), array);
}
});
}
Watchpack.prototype.getTimes = function() {
var directoryWatchers = [];
addWatchersToArray(this.fileWatchers.concat(this.dirWatchers), directoryWatchers);
var obj = Object.create(null);
directoryWatchers.forEach(function(w) {
var times = w.getTimes();
Object.keys(times).forEach(function(file) {
obj[file] = times[file];
});
});
return obj;
};
Watchpack.prototype._fileWatcher = function _fileWatcher(file, watcher) {
watcher.on("change", function(mtime, type) {
this._onChange(file, mtime, file, type);
}.bind(this));
watcher.on("remove", function(type) {
this._onRemove(file, file, type);
}.bind(this));
return watcher;
};
Watchpack.prototype._dirWatcher = function _dirWatcher(item, watcher) {
watcher.on("change", function(file, mtime, type) {
this._onChange(item, mtime, file, type);
}.bind(this));
return watcher;
};
Watchpack.prototype._onChange = function _onChange(item, mtime, file) {
file = file || item;
this.mtimes[file] = mtime;
if(this.paused) return;
this.emit("change", file, mtime);
if(this.aggregateTimeout)
clearTimeout(this.aggregateTimeout);
if(this.aggregatedChanges.indexOf(item) < 0)
this.aggregatedChanges.push(item);
this.aggregateTimeout = setTimeout(this._onTimeout, this.options.aggregateTimeout);
};
Watchpack.prototype._onRemove = function _onRemove(item, file) {
file = file || item;
delete this.mtimes[item];
if(this.paused) return;
this.emit("remove", item);
if(this.aggregateTimeout)
clearTimeout(this.aggregateTimeout);
if(this.aggregatedRemovals.indexOf(item) < 0)
this.aggregatedRemovals.push(item);
this.aggregateTimeout = setTimeout(this._onTimeout, this.options.aggregateTimeout);
};
Watchpack.prototype._onTimeout = function _onTimeout() {
this.aggregateTimeout = 0;
var changes = this.aggregatedChanges;
var removals = this.aggregatedRemovals;
this.aggregatedChanges = [];
this.aggregatedRemovals = [];
this.emit("aggregated", changes, removals);
};

View File

@@ -0,0 +1,74 @@
{
"_args": [
[
"watchpack@1.4.0",
"C:\\Users\\deranjer\\go\\src\\github.com\\deranjer\\goTorrent\\torrent-project"
]
],
"_from": "watchpack@1.4.0",
"_id": "watchpack@1.4.0",
"_inBundle": false,
"_integrity": "sha1-ShRyvLuVK9Cpu0A2gB+VTfs5+qw=",
"_location": "/react-scripts/watchpack",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "watchpack@1.4.0",
"name": "watchpack",
"escapedName": "watchpack",
"rawSpec": "1.4.0",
"saveSpec": null,
"fetchSpec": "1.4.0"
},
"_requiredBy": [
"/react-scripts/webpack"
],
"_resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.4.0.tgz",
"_spec": "1.4.0",
"_where": "C:\\Users\\deranjer\\go\\src\\github.com\\deranjer\\goTorrent\\torrent-project",
"author": {
"name": "Tobias Koppers @sokra"
},
"bugs": {
"url": "https://github.com/webpack/watchpack/issues"
},
"dependencies": {
"async": "^2.1.2",
"chokidar": "^1.7.0",
"graceful-fs": "^4.1.2"
},
"description": "Wrapper library for directory and file watching.",
"devDependencies": {
"codecov.io": "^0.1.6",
"coveralls": "^2.11.2",
"eslint": "^2.9.0",
"istanbul": "^0.4.3",
"mocha": "^2.1.0",
"rimraf": "~2.5.0",
"should": "^8.3.1"
},
"directories": {
"test": "test"
},
"files": [
"lib/"
],
"homepage": "https://github.com/webpack/watchpack",
"license": "MIT",
"main": "./lib/watchpack.js",
"name": "watchpack",
"repository": {
"type": "git",
"url": "git+https://github.com/webpack/watchpack.git"
},
"scripts": {
"cover": "istanbul cover node_modules/mocha/bin/_mocha",
"lint": "eslint lib",
"precover": "npm run lint",
"pretest": "npm run lint",
"test": "mocha",
"travis": "npm run cover -- --report lcovonly"
},
"version": "1.4.0"
}