diff options
author | RaindropsSys <contact@minteck.org> | 2023-04-02 23:03:02 +0200 |
---|---|---|
committer | RaindropsSys <contact@minteck.org> | 2023-04-02 23:03:02 +0200 |
commit | 02eda3e4c9b4ba718f1fff70b7328ed8cdd5e63b (patch) | |
tree | 6d1dec61008998aadc6b69f7e750712794d99324 /includes/external/chvfs | |
parent | f559308a1b42a9036135d764374a8c007b7d70a9 (diff) | |
download | pluralconnect-02eda3e4c9b4ba718f1fff70b7328ed8cdd5e63b.tar.gz pluralconnect-02eda3e4c9b4ba718f1fff70b7328ed8cdd5e63b.tar.bz2 pluralconnect-02eda3e4c9b4ba718f1fff70b7328ed8cdd5e63b.zip |
Updated 35 files, added 11 files and deleted includes/components/search.inc (automated)
Diffstat (limited to 'includes/external/chvfs')
11 files changed, 1240 insertions, 0 deletions
diff --git a/includes/external/chvfs/index.js b/includes/external/chvfs/index.js new file mode 100644 index 0000000..0dfd958 --- /dev/null +++ b/includes/external/chvfs/index.js @@ -0,0 +1,104 @@ +let active = true; +let queue = []; + +const watch = require('node-watch'); +const child_process = require('child_process'); +const fs = require('fs').promises; +const fss = require('fs'); + +process.on('uncaughtException', (e) => { + console.error(e); +}); + +function start() { + console.log("Mounting chvfs..."); + child_process.execSync("mount -t tmpfs -o size=1G chvfs /_ch"); + console.log("Mounted chvfs to /_ch"); + + console.log("Preparing filesystem..."); + child_process.execSync("cp -r /opt/peh_save/* /_ch"); + child_process.execSync("chmod -Rf 777 /_ch"); + console.log("Filesystem is ready"); + + console.log("Watching for changes..."); + watch("/_ch", { recursive: true }, (event, filename) => { + try { + if (!active || !filename) return; + + if (event === "update") { + console.log(filename + " was created or affected"); + + queue.push({ + file: filename, + remove: false + }); + } else if (event === "remove") { + console.log(filename + " was dropped"); + + queue.push({ + file: filename, + remove: true + }); + } + } catch (e) { + console.error(e); + } + }) +} + +function stop() { + active = false; + + console.log("Unmounting chvfs..."); + child_process.execSync("umount -l /_ch"); + console.log("Unmounted chvfs"); +} + +start(); +setInterval(async () => { + for (let item of queue) { + try { + if (item.remove) { + console.log("Dropping " + item.file); + await fs.unlink("/opt/peh_save/" + item.file.substring(5)); + } else { + console.log("Copying " + item.file); + await fs.copyFile(item.file, "/opt/peh_save/" + item.file.substring(5)); + } + } catch (e) { + console.error(e); + } + + queue.splice(0, 1); + } +}); + +process.on('exit', () => { + process.stdout.write("\n"); + + for (let item of queue) { + try { + if (item.remove) { + console.log("Dropping " + item.file); + fss.unlinkSync("/opt/peh_save/" + item.file.substring(5)); + } else { + console.log("Copying " + item.file); + fss.copyFileSync(item.file, "/opt/peh_save/" + item.file.substring(5)); + } + } catch (e) { + console.error(e); + } + + queue.splice(0, 1); + } + + stop(); +}); + +process.on('SIGINT', () => { + process.exit(); +}); + +process.on('SIGTERM', () => { + process.exit(); +});
\ No newline at end of file diff --git a/includes/external/chvfs/node_modules/.package-lock.json b/includes/external/chvfs/node_modules/.package-lock.json new file mode 100644 index 0000000..6f51c8f --- /dev/null +++ b/includes/external/chvfs/node_modules/.package-lock.json @@ -0,0 +1,15 @@ +{ + "name": "chvfs", + "lockfileVersion": 2, + "requires": true, + "packages": { + "node_modules/node-watch": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/node-watch/-/node-watch-0.7.3.tgz", + "integrity": "sha512-3l4E8uMPY1HdMMryPRUAl+oIHtXtyiTlIiESNSVSNxcPfzAFzeTbXFQkZfAwBbo0B1qMSG8nUABx+Gd+YrbKrQ==", + "engines": { + "node": ">=6" + } + } + } +} diff --git a/includes/external/chvfs/node_modules/node-watch/LICENSE b/includes/external/chvfs/node_modules/node-watch/LICENSE new file mode 100644 index 0000000..3718eaa --- /dev/null +++ b/includes/external/chvfs/node_modules/node-watch/LICENSE @@ -0,0 +1,22 @@ +(The MIT License) + +Copyright (c) 2012-2021 Yuan Chuan <yuanchuan23@gmail.com> + +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. diff --git a/includes/external/chvfs/node_modules/node-watch/README.md b/includes/external/chvfs/node_modules/node-watch/README.md new file mode 100644 index 0000000..c0f8bd2 --- /dev/null +++ b/includes/external/chvfs/node_modules/node-watch/README.md @@ -0,0 +1,233 @@ +# node-watch [![Status](https://github.com/yuanchuan/node-watch/actions/workflows/ci.yml/badge.svg)](https://github.com/yuanchuan/node-watch/actions/workflows/ci.yml/badge.svg) + +A wrapper and enhancements for [fs.watch](http://nodejs.org/api/fs.html#fs_fs_watch_filename_options_listener). + +[![NPM](https://nodei.co/npm/node-watch.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/node-watch.png/) + + +## Installation + +```bash +npm install node-watch +``` + +## Example + +```js +var watch = require('node-watch'); + +watch('file_or_dir', { recursive: true }, function(evt, name) { + console.log('%s changed.', name); +}); +``` + +Now it's fast to watch **deep** directories on macOS and Windows, since the `recursive` option is natively supported except on Linux. + +```js +// watch the whole disk +watch('/', { recursive: true }, console.log); +``` + + +## Why? + +* Some editors will generate temporary files which will cause the callback function to be triggered multiple times. +* The callback function will only be triggered once on watching a single file. +* <del>Missing an option to watch a directory recursively.</del> +* Recursive watch is not supported on Linux or in older versions of nodejs. +* Keep it simple, stupid. + + +## Options + +The usage and options of `node-watch` are compatible with [fs.watch](https://nodejs.org/dist/latest-v7.x/docs/api/fs.html#fs_fs_watch_filename_options_listener). +* `persistent: Boolean` (default **true**) +* `recursive: Boolean` (default **false**) +* `encoding: String` (default **'utf8'**) + +**Extra options** + +* `filter: RegExp | Function` + + Return that matches the filter expression. + + ```js + // filter with regular expression + watch('./', { filter: /\.json$/ }); + + // filter with custom function + watch('./', { filter: f => !/node_modules/.test(f) }); + + ``` + + Each file and directory will be passed to the filter to determine whether + it will then be passed to the callback function. Like `Array.filter` does in `JavaScript`. + There are three kinds of return values for filter function: + + * **`true`**: Will be passed to callback. + * **`false`**: Will not be passed to callback. + * **`skip`**: Same with `false`, and skip to watch all its subdirectories. + + On Linux, where the `recursive` option is not natively supported, + it is more efficient to skip ignored directories by returning the `skip` flag: + + ```js + watch('./', { + recursive: true, + filter(f, skip) { + // skip node_modules + if (/\/node_modules/.test(f)) return skip; + // skip .git folder + if (/\.git/.test(f)) return skip; + // only watch for js files + return /\.js$/.test(f); + } + }); + + ``` + + If you prefer glob patterns you can use [minimatch](https://www.npmjs.com/package/minimatch) or [picomatch](https://www.npmjs.com/package/picomatch) + together with filter: + + ```js + const pm = require('picomatch'); + let isMatch = pm('*.js'); + + watch('./', { + filter: f => isMatch(f) + }); + ``` + +* `delay: Number` (in ms, default **200**) + + Delay time of the callback function. + + ```js + // log after 5 seconds + watch('./', { delay: 5000 }, console.log); + ``` + +## Events + +The events provided by the callback function is either `update` or `remove`, which is less confusing to `fs.watch`'s `rename` or `change`. + +```js +watch('./', function(evt, name) { + + if (evt == 'update') { + // on create or modify + } + + if (evt == 'remove') { + // on delete + } + +}); +``` + + +## Watcher object + +The watch function returns a [fs.FSWatcher](https://nodejs.org/api/fs.html#fs_class_fs_fswatcher) like object as the same as `fs.watch` (>= v0.4.0). + +#### Watcher events + +```js +let watcher = watch('./', { recursive: true }); + +watcher.on('change', function(evt, name) { + // callback +}); + +watcher.on('error', function(err) { + // handle error +}); + +watcher.on('ready', function() { + // the watcher is ready to respond to changes +}); +``` + +#### Close + +```js +// close +watcher.close(); + +// is closed? +watcher.isClosed() +``` + +#### List of methods + +* `.on` +* `.once` +* `.emit` +* `.close` +* `.listeners` +* `.setMaxListeners` +* `.getMaxListeners` + +##### Extra methods +* `.isClosed` detect if the watcher is closed +* `.getWatchedPaths` get all the watched paths + + +## Known issues + +**Windows, node < v4.2.5** + + * Failed to detect `remove` event + * Failed to get deleted filename or directory name + +**MacOS, node 0.10.x** + * Will emit double event if the directory name is of one single character. + + +## Misc + +#### 1. Watch multiple files or directories in one place +```js +watch(['file1', 'file2'], console.log); +``` + +#### 2. Customize watch command line tool +```js +#!/usr/bin/env node + +// https://github.com/nodejs/node-v0.x-archive/issues/3211 +require('epipebomb')(); + +let watcher = require('node-watch')( + process.argv[2] || './', { recursive: true }, console.log +); + +process.on('SIGINT', watcher.close); +``` +Monitoring chrome from disk: +```bash +$ watch / | grep -i chrome +``` + +#### 3. Got ENOSPC error? + +If you get ENOSPC error, but you actually have free disk space - it means that your OS watcher limit is too low and you probably want to recursively watch a big tree of files. + +Follow this description to increase the limit: +[https://confluence.jetbrains.com/display/IDEADEV/Inotify+Watches+Limit](https://confluence.jetbrains.com/display/IDEADEV/Inotify+Watches+Limit) + + +## Alternatives + +* [chokidar](https://github.com/paulmillr/chokidar) +* [gaze](https://github.com/shama/gaze) +* [mikeal/watch](https://github.com/mikeal/watch) + +## Contributors + +Thanks goes to [all wonderful people](https://github.com/yuanchuan/node-watch/graphs/contributors) who have helped this project. + +## License +MIT + +Copyright (c) 2012-2021 [yuanchuan](https://github.com/yuanchuan) diff --git a/includes/external/chvfs/node_modules/node-watch/lib/has-native-recursive.js b/includes/external/chvfs/node_modules/node-watch/lib/has-native-recursive.js new file mode 100644 index 0000000..19c1b88 --- /dev/null +++ b/includes/external/chvfs/node_modules/node-watch/lib/has-native-recursive.js @@ -0,0 +1,115 @@ +var fs = require('fs'); +var os = require('os'); +var path = require('path'); +var is = require('./is'); + +var IS_SUPPORT; +var TEMP_DIR = os.tmpdir && os.tmpdir() + || process.env.TMPDIR + || process.env.TEMP + || process.cwd(); + +function TempStack() { + this.stack = []; +} + +TempStack.prototype = { + create: function(type, base) { + var name = path.join(base, + 'node-watch-' + Math.random().toString(16).substr(2) + ); + this.stack.push({ name: name, type: type }); + return name; + }, + write: function(/* file */) { + for (var i = 0; i < arguments.length; ++i) { + fs.writeFileSync(arguments[i], ' '); + } + }, + mkdir: function(/* dirs */) { + for (var i = 0; i < arguments.length; ++i) { + fs.mkdirSync(arguments[i]); + } + }, + cleanup: function(fn) { + try { + var temp; + while ((temp = this.stack.pop())) { + var type = temp.type; + var name = temp.name; + if (type === 'file' && is.file(name)) { + fs.unlinkSync(name); + } + else if (type === 'dir' && is.directory(name)) { + fs.rmdirSync(name); + } + } + } + finally { + if (is.func(fn)) fn(); + } + } +}; + +var pending = false; + +module.exports = function hasNativeRecursive(fn) { + if (!is.func(fn)) { + return false; + } + if (IS_SUPPORT !== undefined) { + return fn(IS_SUPPORT); + } + + if (!pending) { + pending = true; + } + // check again later + else { + return setTimeout(function() { + hasNativeRecursive(fn); + }, 300); + } + + var stack = new TempStack(); + var parent = stack.create('dir', TEMP_DIR); + var child = stack.create('dir', parent); + var file = stack.create('file', child); + + stack.mkdir(parent, child); + + var options = { recursive: true }; + var watcher; + + try { + watcher = fs.watch(parent, options); + } catch (e) { + if (e.code == 'ERR_FEATURE_UNAVAILABLE_ON_PLATFORM') { + return fn(IS_SUPPORT = false); + } else { + throw e; + } + } + + if (!watcher) { + return false; + } + + var timer = setTimeout(function() { + watcher.close(); + stack.cleanup(function() { + fn(IS_SUPPORT = false); + }); + }, 200); + + watcher.on('change', function(evt, name) { + if (path.basename(file) === path.basename(name)) { + watcher.close(); + clearTimeout(timer); + stack.cleanup(function() { + fn(IS_SUPPORT = true); + }); + } + }); + stack.write(file); +} diff --git a/includes/external/chvfs/node_modules/node-watch/lib/is.js b/includes/external/chvfs/node_modules/node-watch/lib/is.js new file mode 100644 index 0000000..ebe0600 --- /dev/null +++ b/includes/external/chvfs/node_modules/node-watch/lib/is.js @@ -0,0 +1,78 @@ +var fs = require('fs'); +var path = require('path'); +var os = require('os'); + +function matchObject(item, str) { + return Object.prototype.toString.call(item) + === '[object ' + str + ']'; +} + +function checkStat(name, fn) { + try { + return fn(name); + } catch (err) { + if (/^(ENOENT|EPERM|EACCES)$/.test(err.code)) { + if (err.code !== 'ENOENT') { + console.warn('Warning: Cannot access %s', name); + } + return false; + } + throw err; + } +} + +var is = { + nil: function(item) { + return item == null; + }, + array: function(item) { + return Array.isArray(item); + }, + emptyObject: function(item) { + for (var key in item) { + return false; + } + return true; + }, + buffer: function(item) { + return Buffer.isBuffer(item); + }, + regExp: function(item) { + return matchObject(item, 'RegExp'); + }, + string: function(item) { + return matchObject(item, 'String'); + }, + func: function(item) { + return typeof item === 'function'; + }, + number: function(item) { + return matchObject(item, 'Number'); + }, + exists: function(name) { + return fs.existsSync(name); + }, + file: function(name) { + return checkStat(name, function(n) { + return fs.statSync(n).isFile() + }); + }, + samePath: function(a, b) { + return path.resolve(a) === path.resolve(b); + }, + directory: function(name) { + return checkStat(name, function(n) { + return fs.statSync(n).isDirectory() + }); + }, + symbolicLink: function(name) { + return checkStat(name, function(n) { + return fs.lstatSync(n).isSymbolicLink(); + }); + }, + windows: function() { + return os.platform() === 'win32'; + } +}; + +module.exports = is; diff --git a/includes/external/chvfs/node_modules/node-watch/lib/watch.d.ts b/includes/external/chvfs/node_modules/node-watch/lib/watch.d.ts new file mode 100644 index 0000000..9eca5d4 --- /dev/null +++ b/includes/external/chvfs/node_modules/node-watch/lib/watch.d.ts @@ -0,0 +1,75 @@ +import { FSWatcher } from 'fs'; + +/** + * Watch for changes on `filename`, where filename is either a file or a directory. + * The second argument is optional. + * + * If `options` is provided as a string, it specifies the encoding. + * Otherwise `options` should be passed as an object. + * + * The listener callback gets two arguments, `(eventType, filePath)`, + * which is the same with `fs.watch`. + * `eventType` is either `update` or `remove`, + * `filePath` is the name of the file which triggered the event. + * + * @param {Filename} filename File or directory to watch. + * @param {Options|string} options + * @param {Function} callback + */ +declare function watch(pathName: PathName): Watcher; +declare function watch(pathName: PathName, options: Options) : Watcher; +declare function watch(pathName: PathName, callback: Callback): Watcher; +declare function watch(pathName: PathName, options: Options, callback: Callback): Watcher; + +type EventType = 'update' | 'remove'; +type Callback = (eventType: EventType, filePath: string) => any; +type PathName = string | Array<string>; +type FilterReturn = boolean | symbol; + +type Options = { + /** + * Indicates whether the process should continue to run + * as long as files are being watched. + * @default true + */ + persistent ?: boolean; + + /** + * Indicates whether all subdirectories should be watched. + * @default false + */ + recursive ?: boolean; + + /** + * Specifies the character encoding to be used for the filename + * passed to the listener. + * @default 'utf8' + */ + encoding ?: string; + + /** + * Only files which pass this filter (when it returns `true`) + * will be sent to the listener. + */ + filter ?: RegExp | ((file: string, skip: symbol) => FilterReturn); + + /** + * Delay time of the callback function. + * @default 200 + */ + delay ?: number; +}; + +declare interface Watcher extends FSWatcher { + /** + * Returns `true` if the watcher has been closed. + */ + isClosed(): boolean; + + /** + * Returns all watched paths. + */ + getWatchedPaths(): Array<string>; +} + +export default watch; diff --git a/includes/external/chvfs/node_modules/node-watch/lib/watch.js b/includes/external/chvfs/node_modules/node-watch/lib/watch.js new file mode 100644 index 0000000..b3d6889 --- /dev/null +++ b/includes/external/chvfs/node_modules/node-watch/lib/watch.js @@ -0,0 +1,530 @@ +var fs = require('fs'); +var path = require('path'); +var util = require('util'); +var events = require('events'); + +var hasNativeRecursive = require('./has-native-recursive'); +var is = require('./is'); + +var EVENT_UPDATE = 'update'; +var EVENT_REMOVE = 'remove'; + +var SKIP_FLAG = Symbol('skip'); + +function hasDup(arr) { + return arr.some(function(v, i, self) { + return self.indexOf(v) !== i; + }); +} + +function unique(arr) { + return arr.filter(function(v, i, self) { + return self.indexOf(v) === i; + }); +} + +// One level flat +function flat1(arr) { + return arr.reduce(function(acc, v) { + return acc.concat(v); + }, []); +} + +function assertEncoding(encoding) { + if (encoding && encoding !== 'buffer' && !Buffer.isEncoding(encoding)) { + throw new Error('Unknown encoding: ' + encoding); + } +} + +function guard(fn) { + if (is.func(fn)) { + return function(arg, action) { + if (fn(arg, false)) action(); + } + } + if (is.regExp(fn)) { + return function(arg, action) { + if (fn.test(arg)) action(); + } + } + return function(arg, action) { + action(); + } +} + +function composeMessage(names) { + return names.map(function(n) { + return is.exists(n) + ? [EVENT_UPDATE, n] + : [EVENT_REMOVE, n]; + }); +} + +function getMessages(cache) { + var filtered = unique(cache); + + // Saving file from an editor? If so, assuming the + // non-existed files in the cache are temporary files + // generated by an editor and thus be filtered. + var reg = /~$|^\.#|^##$/g; + var hasSpecialChar = cache.some(function(c) { + return reg.test(c); + }); + + if (hasSpecialChar) { + var dup = hasDup(cache.map(function(c) { + return c.replace(reg, ''); + })); + if (dup) { + filtered = filtered.filter(function(m) { + return is.exists(m); + }); + } + } + + return composeMessage(filtered); +} + +function debounce(info, fn) { + var timer, cache = []; + var encoding = info.options.encoding; + var delay = info.options.delay; + if (!is.number(delay)) { + delay = 200; + } + function handle() { + getMessages(cache).forEach(function(msg) { + msg[1] = Buffer.from(msg[1]); + if (encoding !== 'buffer') { + msg[1] = msg[1].toString(encoding); + } + fn.apply(null, msg); + }); + timer = null; + cache = []; + } + return function(rawEvt, name) { + cache.push(name); + if (!timer) { + timer = setTimeout(handle, delay); + } + } +} + +function createDupsFilter() { + var memo = {}; + return function(fn) { + return function(evt, name) { + memo[evt + name] = [evt, name]; + setTimeout(function() { + Object.keys(memo).forEach(function(n) { + fn.apply(null, memo[n]); + }); + memo = {}; + }); + } + } +} + +function getSubDirectories(dir, fn, done = function() {}) { + if (is.directory(dir)) { + fs.readdir(dir, function(err, all) { + if (err) { + // don't throw permission errors. + if (/^(EPERM|EACCES)$/.test(err.code)) { + console.warn('Warning: Cannot access %s.', dir); + } else { + throw err; + } + } + else { + all.forEach(function(f) { + var sdir = path.join(dir, f); + if (is.directory(sdir)) fn(sdir); + }); + done(); + } + }); + } else { + done(); + } +} + +function semaphore(final) { + var counter = 0; + return function start() { + counter++; + return function stop() { + counter--; + if (counter === 0) final(); + }; + }; +} + +function nullCounter() { + return function nullStop() {}; +} + +function shouldNotSkip(filePath, filter) { + // watch it only if the filter is not function + // or not being skipped explicitly. + return !is.func(filter) || filter(filePath, SKIP_FLAG) !== SKIP_FLAG; +} + +var deprecationWarning = util.deprecate( + function() {}, + '(node-watch) First param in callback function\ + is replaced with event name since 0.5.0, use\ + `(evt, filename) => {}` if you want to get the filename' +); + +function Watcher() { + events.EventEmitter.call(this); + this.watchers = {}; + this._isReady = false; + this._isClosed = false; +} + +util.inherits(Watcher, events.EventEmitter); + +Watcher.prototype.expose = function() { + var expose = {}; + var self = this; + var methods = [ + 'on', 'emit', 'once', + 'close', 'isClosed', + 'listeners', 'setMaxListeners', 'getMaxListeners', + 'getWatchedPaths' + ]; + methods.forEach(function(name) { + expose[name] = function() { + return self[name].apply(self, arguments); + } + }); + return expose; +} + +Watcher.prototype.isClosed = function() { + return this._isClosed; +} + +Watcher.prototype.close = function(fullPath) { + var self = this; + if (fullPath) { + var watcher = this.watchers[fullPath]; + if (watcher && watcher.close) { + watcher.close(); + delete self.watchers[fullPath]; + } + getSubDirectories(fullPath, function(fpath) { + self.close(fpath); + }); + } + else { + Object.keys(self.watchers).forEach(function(fpath) { + var watcher = self.watchers[fpath]; + if (watcher && watcher.close) { + watcher.close(); + } + }); + this.watchers = {}; + } + // Do not close the Watcher unless all child watchers are closed. + // https://github.com/yuanchuan/node-watch/issues/75 + if (is.emptyObject(self.watchers)) { + // should emit once + if (!this._isClosed) { + this._isClosed = true; + process.nextTick(emitClose, this); + } + } +} + +Watcher.prototype.getWatchedPaths = function(fn) { + if (is.func(fn)) { + var self = this; + if (self._isReady) { + fn(Object.keys(self.watchers)); + } else { + self.on('ready', function() { + fn(Object.keys(self.watchers)); + }); + } + } +} + +function emitReady(self) { + if (!self._isReady) { + self._isReady = true; + // do not call emit for 'ready' until after watch() has returned, + // so that consumer can call on(). + process.nextTick(function () { + self.emit('ready'); + }); + } +} + +function emitClose(self) { + self.emit('close'); +} + +Watcher.prototype.add = function(watcher, info) { + var self = this; + info = info || { fpath: '' }; + var watcherPath = path.resolve(info.fpath); + this.watchers[watcherPath] = watcher; + + // Internal callback for handling fs.FSWatcher 'change' events + var internalOnChange = function(rawEvt, rawName) { + if (self.isClosed()) { + return; + } + + // normalise lack of name and convert to full path + var name = rawName; + if (is.nil(name)) { + name = ''; + } + name = path.join(info.fpath, name); + + if (info.options.recursive) { + hasNativeRecursive(function(has) { + if (!has) { + var fullPath = path.resolve(name); + // remove watcher on removal + if (!is.exists(name)) { + self.close(fullPath); + } + // watch new created directory + else { + var shouldWatch = is.directory(name) + && !self.watchers[fullPath] + && shouldNotSkip(name, info.options.filter); + + if (shouldWatch) { + self.watchDirectory(name, info.options); + } + } + } + }); + } + + handlePublicEvents(rawEvt, name); + }; + + // Debounced based on the 'delay' option + var handlePublicEvents = debounce(info, function (evt, name) { + // watch single file + if (info.compareName) { + if (info.compareName(name)) { + self.emit('change', evt, name); + } + } + // watch directory + else { + var filterGuard = guard(info.options.filter); + filterGuard(name, function() { + if (self.flag) self.flag = ''; + else self.emit('change', evt, name); + }); + } + }); + + watcher.on('error', function(err) { + if (self.isClosed()) { + return; + } + if (is.windows() && err.code === 'EPERM') { + watcher.emit('change', EVENT_REMOVE, info.fpath && ''); + self.flag = 'windows-error'; + self.close(watcherPath); + } else { + self.emit('error', err); + } + }); + + watcher.on('change', internalOnChange); +} + +Watcher.prototype.watchFile = function(file, options, fn) { + var parent = path.join(file, '../'); + var opts = Object.assign({}, options, { + // no filter for single file + filter: null, + encoding: 'utf8' + }); + + // no need to watch recursively + delete opts.recursive; + + var watcher = fs.watch(parent, opts); + this.add(watcher, { + type: 'file', + fpath: parent, + options: Object.assign({}, opts, { + encoding: options.encoding + }), + compareName: function(n) { + return is.samePath(n, file); + } + }); + + if (is.func(fn)) { + if (fn.length === 1) deprecationWarning(); + this.on('change', fn); + } +} + +Watcher.prototype.watchDirectory = function(dir, options, fn, counter = nullCounter) { + var self = this; + var done = counter(); + hasNativeRecursive(function(has) { + // always specify recursive + options.recursive = !!options.recursive; + // using utf8 internally + var opts = Object.assign({}, options, { + encoding: 'utf8' + }); + if (!has) { + delete opts.recursive; + } + + // check if it's closed before calling watch. + if (self._isClosed) { + done(); + return self.close(); + } + + var watcher = fs.watch(dir, opts); + + self.add(watcher, { + type: 'dir', + fpath: dir, + options: options + }); + + if (is.func(fn)) { + if (fn.length === 1) deprecationWarning(); + self.on('change', fn); + } + + if (options.recursive && !has) { + getSubDirectories(dir, function(d) { + if (shouldNotSkip(d, options.filter)) { + self.watchDirectory(d, options, null, counter); + } + }, counter()); + } + + done(); + }); +} + +function composeWatcher(watchers) { + var watcher = new Watcher(); + var filterDups = createDupsFilter(); + var counter = watchers.length; + + watchers.forEach(function(w) { + w.on('change', filterDups(function(evt, name) { + watcher.emit('change', evt, name); + })); + w.on('error', function(err) { + watcher.emit('error', err); + }); + w.on('ready', function() { + if (!(--counter)) { + emitReady(watcher); + } + }); + }); + + watcher.close = function() { + watchers.forEach(function(w) { + w.close(); + }); + process.nextTick(emitClose, watcher); + } + + watcher.getWatchedPaths = function(fn) { + if (is.func(fn)) { + var promises = watchers.map(function(w) { + return new Promise(function(resolve) { + w.getWatchedPaths(resolve); + }); + }); + Promise.all(promises).then(function(result) { + var ret = unique(flat1(result)); + fn(ret); + }); + } + } + + return watcher.expose(); +} + +function watch(fpath, options, fn) { + var watcher = new Watcher(); + + if (is.buffer(fpath)) { + fpath = fpath.toString(); + } + + if (!is.array(fpath) && !is.exists(fpath)) { + watcher.emit('error', + new Error(fpath + ' does not exist.') + ); + } + + if (is.string(options)) { + options = { + encoding: options + } + } + + if (is.func(options)) { + fn = options; + options = {}; + } + + if (arguments.length < 2) { + options = {}; + } + + if (options.encoding) { + assertEncoding(options.encoding); + } else { + options.encoding = 'utf8'; + } + + if (is.array(fpath)) { + if (fpath.length === 1) { + return watch(fpath[0], options, fn); + } + var filterDups = createDupsFilter(); + return composeWatcher(unique(fpath).map(function(f) { + var w = watch(f, options); + if (is.func(fn)) { + w.on('change', filterDups(fn)); + } + return w; + })); + } + + if (is.file(fpath)) { + watcher.watchFile(fpath, options, fn); + emitReady(watcher); + } + + else if (is.directory(fpath)) { + var counter = semaphore(function () { + emitReady(watcher); + }); + watcher.watchDirectory(fpath, options, fn, counter); + } + + return watcher.expose(); +} + +module.exports = watch; +module.exports.default = watch; diff --git a/includes/external/chvfs/node_modules/node-watch/package.json b/includes/external/chvfs/node_modules/node-watch/package.json new file mode 100644 index 0000000..241dc81 --- /dev/null +++ b/includes/external/chvfs/node_modules/node-watch/package.json @@ -0,0 +1,36 @@ +{ + "description": "A wrapper and enhancements for fs.watch", + "license": "MIT", + "name": "node-watch", + "repository": { + "url": "git://github.com/yuanchuan/node-watch.git", + "type": "git" + }, + "keywords": [ + "fs.watch", + "watch", + "watchfile" + ], + "version": "0.7.3", + "bugs": { + "url": "https://github.com/yuanchuan/node-watch/issues" + }, + "url": "https://github.com/yuanchuan/node-watch", + "author": "yuanchuan <yuanchuan23@gmail.com> (http://yuanchuan.name)", + "main": "./lib/watch", + "types": "./lib/watch.d.ts", + "files": [ + "lib/" + ], + "homepage": "https://github.com/yuanchuan/node-watch#readme", + "scripts": { + "test": "mocha test/test.js --exit --slow 500" + }, + "engines": { + "node": ">=6" + }, + "devDependencies": { + "fs-extra": "^7.0.1", + "mocha": "^5.2.0" + } +} diff --git a/includes/external/chvfs/package-lock.json b/includes/external/chvfs/package-lock.json new file mode 100644 index 0000000..e2d2ba4 --- /dev/null +++ b/includes/external/chvfs/package-lock.json @@ -0,0 +1,27 @@ +{ + "name": "chvfs", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "dependencies": { + "node-watch": "^0.7.3" + } + }, + "node_modules/node-watch": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/node-watch/-/node-watch-0.7.3.tgz", + "integrity": "sha512-3l4E8uMPY1HdMMryPRUAl+oIHtXtyiTlIiESNSVSNxcPfzAFzeTbXFQkZfAwBbo0B1qMSG8nUABx+Gd+YrbKrQ==", + "engines": { + "node": ">=6" + } + } + }, + "dependencies": { + "node-watch": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/node-watch/-/node-watch-0.7.3.tgz", + "integrity": "sha512-3l4E8uMPY1HdMMryPRUAl+oIHtXtyiTlIiESNSVSNxcPfzAFzeTbXFQkZfAwBbo0B1qMSG8nUABx+Gd+YrbKrQ==" + } + } +} diff --git a/includes/external/chvfs/package.json b/includes/external/chvfs/package.json new file mode 100644 index 0000000..8a3cbee --- /dev/null +++ b/includes/external/chvfs/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "node-watch": "^0.7.3" + } +} |