401 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			401 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 
								 | 
							
								'use strict';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Object.defineProperty(exports, '__esModule', {
							 | 
						||
| 
								 | 
							
								  value: true
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								exports.default = WatchmanWatcher;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function _fs() {
							 | 
						||
| 
								 | 
							
								  const data = _interopRequireDefault(require('fs'));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  _fs = function _fs() {
							 | 
						||
| 
								 | 
							
								    return data;
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return data;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function _path() {
							 | 
						||
| 
								 | 
							
								  const data = _interopRequireDefault(require('path'));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  _path = function _path() {
							 | 
						||
| 
								 | 
							
								    return data;
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return data;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function _assert() {
							 | 
						||
| 
								 | 
							
								  const data = _interopRequireDefault(require('assert'));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  _assert = function _assert() {
							 | 
						||
| 
								 | 
							
								    return data;
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return data;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function _events() {
							 | 
						||
| 
								 | 
							
								  const data = require('events');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  _events = function _events() {
							 | 
						||
| 
								 | 
							
								    return data;
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return data;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function _fbWatchman() {
							 | 
						||
| 
								 | 
							
								  const data = _interopRequireDefault(require('fb-watchman'));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  _fbWatchman = function _fbWatchman() {
							 | 
						||
| 
								 | 
							
								    return data;
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return data;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function _common() {
							 | 
						||
| 
								 | 
							
								  const data = _interopRequireDefault(require('sane/src/common'));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  _common = function _common() {
							 | 
						||
| 
								 | 
							
								    return data;
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return data;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function _recrawlWarningDedupe() {
							 | 
						||
| 
								 | 
							
								  const data = _interopRequireDefault(
							 | 
						||
| 
								 | 
							
								    require('sane/src/utils/recrawl-warning-dedupe')
							 | 
						||
| 
								 | 
							
								  );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  _recrawlWarningDedupe = function _recrawlWarningDedupe() {
							 | 
						||
| 
								 | 
							
								    return data;
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return data;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function _interopRequireDefault(obj) {
							 | 
						||
| 
								 | 
							
								  return obj && obj.__esModule ? obj : {default: obj};
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * This source code is licensed under the MIT license found in the
							 | 
						||
| 
								 | 
							
								 * LICENSE file in the root directory of this source tree.
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								const CHANGE_EVENT = _common().default.CHANGE_EVENT;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const DELETE_EVENT = _common().default.DELETE_EVENT;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const ADD_EVENT = _common().default.ADD_EVENT;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const ALL_EVENT = _common().default.ALL_EVENT;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const SUB_NAME = 'sane-sub';
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Watches `dir`.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @class PollWatcher
							 | 
						||
| 
								 | 
							
								 * @param String dir
							 | 
						||
| 
								 | 
							
								 * @param {Object} opts
							 | 
						||
| 
								 | 
							
								 * @public
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function WatchmanWatcher(dir, opts) {
							 | 
						||
| 
								 | 
							
								  _common().default.assignOptions(this, opts);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  this.root = _path().default.resolve(dir);
							 | 
						||
| 
								 | 
							
								  this.init();
							 | 
						||
| 
								 | 
							
								} // eslint-disable-next-line no-proto
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								WatchmanWatcher.prototype.__proto__ = _events().EventEmitter.prototype;
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Run the watchman `watch` command on the root and subscribe to changes.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @private
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								WatchmanWatcher.prototype.init = function() {
							 | 
						||
| 
								 | 
							
								  if (this.client) {
							 | 
						||
| 
								 | 
							
								    this.client.removeAllListeners();
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  const self = this;
							 | 
						||
| 
								 | 
							
								  this.client = new (_fbWatchman()).default.Client();
							 | 
						||
| 
								 | 
							
								  this.client.on('error', error => {
							 | 
						||
| 
								 | 
							
								    self.emit('error', error);
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								  this.client.on('subscription', this.handleChangeEvent.bind(this));
							 | 
						||
| 
								 | 
							
								  this.client.on('end', () => {
							 | 
						||
| 
								 | 
							
								    console.warn('[sane] Warning: Lost connection to watchman, reconnecting..');
							 | 
						||
| 
								 | 
							
								    self.init();
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								  this.watchProjectInfo = null;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function getWatchRoot() {
							 | 
						||
| 
								 | 
							
								    return self.watchProjectInfo ? self.watchProjectInfo.root : self.root;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function onCapability(error, resp) {
							 | 
						||
| 
								 | 
							
								    if (handleError(self, error)) {
							 | 
						||
| 
								 | 
							
								      // The Watchman watcher is unusable on this system, we cannot continue
							 | 
						||
| 
								 | 
							
								      return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    handleWarning(resp);
							 | 
						||
| 
								 | 
							
								    self.capabilities = resp.capabilities;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (self.capabilities.relative_root) {
							 | 
						||
| 
								 | 
							
								      self.client.command(['watch-project', getWatchRoot()], onWatchProject);
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								      self.client.command(['watch', getWatchRoot()], onWatch);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function onWatchProject(error, resp) {
							 | 
						||
| 
								 | 
							
								    if (handleError(self, error)) {
							 | 
						||
| 
								 | 
							
								      return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    handleWarning(resp);
							 | 
						||
| 
								 | 
							
								    self.watchProjectInfo = {
							 | 
						||
| 
								 | 
							
								      relativePath: resp.relative_path ? resp.relative_path : '',
							 | 
						||
| 
								 | 
							
								      root: resp.watch
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								    self.client.command(['clock', getWatchRoot()], onClock);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function onWatch(error, resp) {
							 | 
						||
| 
								 | 
							
								    if (handleError(self, error)) {
							 | 
						||
| 
								 | 
							
								      return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    handleWarning(resp);
							 | 
						||
| 
								 | 
							
								    self.client.command(['clock', getWatchRoot()], onClock);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function onClock(error, resp) {
							 | 
						||
| 
								 | 
							
								    if (handleError(self, error)) {
							 | 
						||
| 
								 | 
							
								      return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    handleWarning(resp);
							 | 
						||
| 
								 | 
							
								    const options = {
							 | 
						||
| 
								 | 
							
								      fields: ['name', 'exists', 'new'],
							 | 
						||
| 
								 | 
							
								      since: resp.clock
							 | 
						||
| 
								 | 
							
								    }; // If the server has the wildmatch capability available it supports
							 | 
						||
| 
								 | 
							
								    // the recursive **/*.foo style match and we can offload our globs
							 | 
						||
| 
								 | 
							
								    // to the watchman server.  This saves both on data size to be
							 | 
						||
| 
								 | 
							
								    // communicated back to us and compute for evaluating the globs
							 | 
						||
| 
								 | 
							
								    // in our node process.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (self.capabilities.wildmatch) {
							 | 
						||
| 
								 | 
							
								      if (self.globs.length === 0) {
							 | 
						||
| 
								 | 
							
								        if (!self.dot) {
							 | 
						||
| 
								 | 
							
								          // Make sure we honor the dot option if even we're not using globs.
							 | 
						||
| 
								 | 
							
								          options.expression = [
							 | 
						||
| 
								 | 
							
								            'match',
							 | 
						||
| 
								 | 
							
								            '**',
							 | 
						||
| 
								 | 
							
								            'wholename',
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								              includedotfiles: false
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								          ];
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      } else {
							 | 
						||
| 
								 | 
							
								        options.expression = ['anyof'];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        for (const i in self.globs) {
							 | 
						||
| 
								 | 
							
								          options.expression.push([
							 | 
						||
| 
								 | 
							
								            'match',
							 | 
						||
| 
								 | 
							
								            self.globs[i],
							 | 
						||
| 
								 | 
							
								            'wholename',
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								              includedotfiles: self.dot
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								          ]);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if (self.capabilities.relative_root) {
							 | 
						||
| 
								 | 
							
								      options.relative_root = self.watchProjectInfo.relativePath;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    self.client.command(
							 | 
						||
| 
								 | 
							
								      ['subscribe', getWatchRoot(), SUB_NAME, options],
							 | 
						||
| 
								 | 
							
								      onSubscribe
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function onSubscribe(error, resp) {
							 | 
						||
| 
								 | 
							
								    if (handleError(self, error)) {
							 | 
						||
| 
								 | 
							
								      return;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    handleWarning(resp);
							 | 
						||
| 
								 | 
							
								    self.emit('ready');
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  self.client.capabilityCheck(
							 | 
						||
| 
								 | 
							
								    {
							 | 
						||
| 
								 | 
							
								      optional: ['wildmatch', 'relative_root']
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								    onCapability
							 | 
						||
| 
								 | 
							
								  );
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Handles a change event coming from the subscription.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param {Object} resp
							 | 
						||
| 
								 | 
							
								 * @private
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								WatchmanWatcher.prototype.handleChangeEvent = function(resp) {
							 | 
						||
| 
								 | 
							
								  _assert().default.equal(
							 | 
						||
| 
								 | 
							
								    resp.subscription,
							 | 
						||
| 
								 | 
							
								    SUB_NAME,
							 | 
						||
| 
								 | 
							
								    'Invalid subscription event.'
							 | 
						||
| 
								 | 
							
								  );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (resp.is_fresh_instance) {
							 | 
						||
| 
								 | 
							
								    this.emit('fresh_instance');
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (resp.is_fresh_instance) {
							 | 
						||
| 
								 | 
							
								    this.emit('fresh_instance');
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (Array.isArray(resp.files)) {
							 | 
						||
| 
								 | 
							
								    resp.files.forEach(this.handleFileChange, this);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Handles a single change event record.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param {Object} changeDescriptor
							 | 
						||
| 
								 | 
							
								 * @private
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								WatchmanWatcher.prototype.handleFileChange = function(changeDescriptor) {
							 | 
						||
| 
								 | 
							
								  const self = this;
							 | 
						||
| 
								 | 
							
								  let absPath;
							 | 
						||
| 
								 | 
							
								  let relativePath;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (this.capabilities.relative_root) {
							 | 
						||
| 
								 | 
							
								    relativePath = changeDescriptor.name;
							 | 
						||
| 
								 | 
							
								    absPath = _path().default.join(
							 | 
						||
| 
								 | 
							
								      this.watchProjectInfo.root,
							 | 
						||
| 
								 | 
							
								      this.watchProjectInfo.relativePath,
							 | 
						||
| 
								 | 
							
								      relativePath
							 | 
						||
| 
								 | 
							
								    );
							 | 
						||
| 
								 | 
							
								  } else {
							 | 
						||
| 
								 | 
							
								    absPath = _path().default.join(this.root, changeDescriptor.name);
							 | 
						||
| 
								 | 
							
								    relativePath = changeDescriptor.name;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (
							 | 
						||
| 
								 | 
							
								    !(self.capabilities.wildmatch && !this.hasIgnore) &&
							 | 
						||
| 
								 | 
							
								    !_common().default.isFileIncluded(
							 | 
						||
| 
								 | 
							
								      this.globs,
							 | 
						||
| 
								 | 
							
								      this.dot,
							 | 
						||
| 
								 | 
							
								      this.doIgnore,
							 | 
						||
| 
								 | 
							
								      relativePath
							 | 
						||
| 
								 | 
							
								    )
							 | 
						||
| 
								 | 
							
								  ) {
							 | 
						||
| 
								 | 
							
								    return;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (!changeDescriptor.exists) {
							 | 
						||
| 
								 | 
							
								    self.emitEvent(DELETE_EVENT, relativePath, self.root);
							 | 
						||
| 
								 | 
							
								  } else {
							 | 
						||
| 
								 | 
							
								    _fs().default.lstat(absPath, (error, stat) => {
							 | 
						||
| 
								 | 
							
								      // Files can be deleted between the event and the lstat call
							 | 
						||
| 
								 | 
							
								      // the most reliable thing to do here is to ignore the event.
							 | 
						||
| 
								 | 
							
								      if (error && error.code === 'ENOENT') {
							 | 
						||
| 
								 | 
							
								        return;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (handleError(self, error)) {
							 | 
						||
| 
								 | 
							
								        return;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      const eventType = changeDescriptor.new ? ADD_EVENT : CHANGE_EVENT; // Change event on dirs are mostly useless.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (!(eventType === CHANGE_EVENT && stat.isDirectory())) {
							 | 
						||
| 
								 | 
							
								        self.emitEvent(eventType, relativePath, self.root, stat);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    });
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Dispatches the event.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param {string} eventType
							 | 
						||
| 
								 | 
							
								 * @param {string} filepath
							 | 
						||
| 
								 | 
							
								 * @param {string} root
							 | 
						||
| 
								 | 
							
								 * @param {fs.Stat} stat
							 | 
						||
| 
								 | 
							
								 * @private
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								WatchmanWatcher.prototype.emitEvent = function(
							 | 
						||
| 
								 | 
							
								  eventType,
							 | 
						||
| 
								 | 
							
								  filepath,
							 | 
						||
| 
								 | 
							
								  root,
							 | 
						||
| 
								 | 
							
								  stat
							 | 
						||
| 
								 | 
							
								) {
							 | 
						||
| 
								 | 
							
								  this.emit(eventType, filepath, root, stat);
							 | 
						||
| 
								 | 
							
								  this.emit(ALL_EVENT, eventType, filepath, root, stat);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Closes the watcher.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param {function} callback
							 | 
						||
| 
								 | 
							
								 * @private
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								WatchmanWatcher.prototype.close = function(callback) {
							 | 
						||
| 
								 | 
							
								  this.client.removeAllListeners();
							 | 
						||
| 
								 | 
							
								  this.client.end();
							 | 
						||
| 
								 | 
							
								  callback && callback(null, true);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Handles an error and returns true if exists.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param {WatchmanWatcher} self
							 | 
						||
| 
								 | 
							
								 * @param {Error} error
							 | 
						||
| 
								 | 
							
								 * @private
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function handleError(self, error) {
							 | 
						||
| 
								 | 
							
								  if (error != null) {
							 | 
						||
| 
								 | 
							
								    self.emit('error', error);
							 | 
						||
| 
								 | 
							
								    return true;
							 | 
						||
| 
								 | 
							
								  } else {
							 | 
						||
| 
								 | 
							
								    return false;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * Handles a warning in the watchman resp object.
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * @param {object} resp
							 | 
						||
| 
								 | 
							
								 * @private
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function handleWarning(resp) {
							 | 
						||
| 
								 | 
							
								  if ('warning' in resp) {
							 | 
						||
| 
								 | 
							
								    if (_recrawlWarningDedupe().default.isRecrawlWarningDupe(resp.warning)) {
							 | 
						||
| 
								 | 
							
								      return true;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    console.warn(resp.warning);
							 | 
						||
| 
								 | 
							
								    return true;
							 | 
						||
| 
								 | 
							
								  } else {
							 | 
						||
| 
								 | 
							
								    return false;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 |