Repository URL to install this package:
|
Version:
1.7.0-16898 ▾
|
/*
* Copyright (c) 2013 - present Adobe Systems Incorporated. All rights reserved.
*
* 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.
*
*/
/*jslint vars: true, plusplus: true, devel: true, node: true, nomen: true, indent: 4, maxerr: 50 */
"use strict";
var fspath = require("path"),
fs = require("fs"),
os = require("os"),
fsevents;
/*
* NOTE: The fsevents package is a temporary solution for file-watching on darwin.
* Node's native fs.watch call would be preferable, but currently has a hard limit
* of 451 watched directories and fails silently after that! In the next stable
* version of Node (0.12), fs.watch on darwin will support a new "recursive" option
* that will allow us to only request a single watched path per directory structure.
* When that is stable, we should switch back to fs.watch for all platforms, and
* we should use the recursive option where available. As of January 2014, the
* current experimental Node branch (0.11) only supports the recursive option for
* darwin.
*
* In the meantime, the fsevents package makes direct use of the Mac OS fsevents
* API to provide file watching capabilities. Its behavior is also recursive
* (like fs.watch with the recursive option), but the events it emits are not
* exactly the same as those emitted by Node watchers. Consequently, we require,
* for now, dual implementations of the FileWatcher domain.
*
* ALSO NOTE: the fsevents package as installed by NPM is not suitable for
* distribution with Brackets! The problem is that the native code embedded in
* the fsevents module is compiled by default for x86-64, but the Brackets-node
* process is compiled for x86-32. Consequently, the fsevents module must be
* compiled manually, which is why it is checked into Brackets source control
* and not managed by NPM. Changing compilation from 64- to 32-bit just requires
* changing a couple of definitions in the .gyp file used to build fsevents.
*/
if (process.platform === "darwin") {
fsevents = require("fsevents");
} else if (process.platform === "win32") {
var version = os.release();
// XP will use node's built in file watcher module.
if (version && version.length > 0 && version[0] !== "5") {
fsevents = require("fsevents_win/fsevents_win");
}
}
var _domainManager,
_watcherMap = {};
/**
* @private
* Un-watch a file or directory.
* @param {string} path File or directory to unwatch.
*/
function _unwatchPath(path) {
var watcher = _watcherMap[path];
if (watcher) {
try {
if (fsevents) {
watcher.stop();
} else {
watcher.close();
}
} catch (err) {
console.warn("Failed to unwatch file " + path + ": " + (err && err.message));
} finally {
delete _watcherMap[path];
}
}
}
/**
* Un-watch a file or directory. For directories, unwatch all descendants.
* @param {string} path File or directory to unwatch.
*/
function unwatchPath(path) {
Object.keys(_watcherMap).forEach(function (keyPath) {
if (keyPath.indexOf(path) === 0) {
_unwatchPath(keyPath);
}
});
}
/**
* Watch a file or directory.
* @param {string} path File or directory to watch.
*/
function watchPath(path) {
if (_watcherMap.hasOwnProperty(path)) {
return;
}
try {
var watcher;
if (fsevents) {
watcher = fsevents(path);
watcher.on("change", function (filename, info) {
var parent = filename && (fspath.dirname(filename) + "/"),
name = filename && fspath.basename(filename),
type;
switch (info.event) {
case "modified": // triggered by file content changes
case "unknown": // triggered by metatdata-only changes
type = "change";
break;
default:
type = "rename";
}
_domainManager.emitEvent("fileWatcher", "change", [parent, type, name]);
});
} else {
watcher = fs.watch(path, {persistent: false}, function (event, filename) {
// File/directory changes are emitted as "change" events on the fileWatcher domain.
_domainManager.emitEvent("fileWatcher", "change", [path, event, filename]);
});
}
_watcherMap[path] = watcher;
watcher.on("error", function (err) {
console.error("Error watching file " + path + ": " + (err && err.message));
unwatchPath(path);
});
} catch (err) {
console.warn("Failed to watch file " + path + ": " + (err && err.message));
}
}
/**
* Un-watch all files and directories.
*/
function unwatchAll() {
var path;
for (path in _watcherMap) {
if (_watcherMap.hasOwnProperty(path)) {
unwatchPath(path);
}
}
}
/**
* Initialize the "fileWatcher" domain.
* The fileWatcher domain handles watching and un-watching directories.
*/
function init(domainManager) {
if (!domainManager.hasDomain("fileWatcher")) {
domainManager.registerDomain("fileWatcher", {major: 0, minor: 1});
}
domainManager.registerCommand(
"fileWatcher",
"watchPath",
watchPath,
false,
"Start watching a file or directory",
[{
name: "path",
type: "string",
description: "absolute filesystem path of the file or directory to watch"
}]
);
domainManager.registerCommand(
"fileWatcher",
"unwatchPath",
unwatchPath,
false,
"Stop watching a single file or a directory and it's descendants",
[{
name: "path",
type: "string",
description: "absolute filesystem path of the file or directory to unwatch"
}]
);
domainManager.registerCommand(
"fileWatcher",
"unwatchAll",
unwatchAll,
false,
"Stop watching all files and directories"
);
domainManager.registerEvent(
"fileWatcher",
"change",
[
{name: "path", type: "string"},
{name: "event", type: "string"},
{name: "filename", type: "string"}
]
);
_domainManager = domainManager;
}
exports.init = init;