mirror of
				https://scm.univ-tours.fr/22107988t/rappaurio-sae501_502.git
				synced 2025-11-04 02:45:22 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			303 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			303 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
// Adapted from work by jorge@jorgechamorro.com on 2010-11-25
 | 
						|
(function () {
 | 
						|
  "use strict";
 | 
						|
 | 
						|
  function noop() {}
 | 
						|
 | 
						|
  var fs = require('fs')
 | 
						|
    , forEachAsync = require('foreachasync').forEachAsync
 | 
						|
    , EventEmitter = require('events').EventEmitter
 | 
						|
    , TypeEmitter = require('./node-type-emitter')
 | 
						|
    , util = require('util')
 | 
						|
    , path = require('path')
 | 
						|
    ;
 | 
						|
 | 
						|
  function appendToDirs(stat) {
 | 
						|
    /*jshint validthis:true*/
 | 
						|
    if(stat.flag && stat.flag === NO_DESCEND) { return; }
 | 
						|
    this.push(stat.name);
 | 
						|
  }
 | 
						|
 | 
						|
  function wFilesHandlerWrapper(items) {
 | 
						|
    /*jshint validthis:true*/
 | 
						|
    this._wFilesHandler(noop, items);
 | 
						|
  }
 | 
						|
 | 
						|
  function Walker(pathname, options, sync) {
 | 
						|
    EventEmitter.call(this);
 | 
						|
 | 
						|
    var me = this
 | 
						|
      ;
 | 
						|
 | 
						|
    options = options || {};
 | 
						|
    me._wStat = options.followLinks && 'stat' || 'lstat';
 | 
						|
    me._wStatSync = me._wStat + 'Sync';
 | 
						|
    me._wsync = sync;
 | 
						|
    me._wq = [];
 | 
						|
    me._wqueue = [me._wq];
 | 
						|
    me._wcurpath = undefined;
 | 
						|
    me._wfilters = options.filters || [];
 | 
						|
    me._wfirstrun = true;
 | 
						|
    me._wcurpath = pathname;
 | 
						|
 | 
						|
    if (me._wsync) {
 | 
						|
      //console.log('_walkSync');
 | 
						|
      me._wWalk = me._wWalkSync;
 | 
						|
    } else {
 | 
						|
      //console.log('_walkASync');
 | 
						|
      me._wWalk = me._wWalkAsync;
 | 
						|
    }
 | 
						|
 | 
						|
    options.listeners = options.listeners || {};
 | 
						|
    Object.keys(options.listeners).forEach(function (event) {
 | 
						|
      var callbacks = options.listeners[event]
 | 
						|
        ;
 | 
						|
 | 
						|
      if ('function' === typeof callbacks) {
 | 
						|
        callbacks = [callbacks];
 | 
						|
      }
 | 
						|
 | 
						|
      callbacks.forEach(function (callback) {
 | 
						|
        me.on(event, callback);
 | 
						|
      });
 | 
						|
    });
 | 
						|
 | 
						|
    me._wWalk();
 | 
						|
  }
 | 
						|
 | 
						|
  // Inherits must come before prototype additions
 | 
						|
  util.inherits(Walker, EventEmitter);
 | 
						|
 | 
						|
  Walker.prototype._wLstatHandler = function (err, stat) {
 | 
						|
    var me = this
 | 
						|
      ;
 | 
						|
 | 
						|
    stat = stat || {};
 | 
						|
    stat.name = me._wcurfile;
 | 
						|
 | 
						|
    if (err) {
 | 
						|
      stat.error = err;
 | 
						|
      //me.emit('error', curpath, stat);
 | 
						|
      // TODO v3.0 (don't noop the next if there are listeners)
 | 
						|
      me.emit('nodeError', me._wcurpath, stat, noop);
 | 
						|
      me._wfnodegroups.errors.push(stat);
 | 
						|
      me._wCurFileCallback();
 | 
						|
    } else {
 | 
						|
      TypeEmitter.sortFnodesByType(stat, me._wfnodegroups);
 | 
						|
      // NOTE: wCurFileCallback doesn't need thisness, so this is okay
 | 
						|
      TypeEmitter.emitNodeType(me, me._wcurpath, stat, me._wCurFileCallback, me);
 | 
						|
    }
 | 
						|
  };
 | 
						|
  Walker.prototype._wFilesHandler = function (cont, file) {
 | 
						|
    var statPath
 | 
						|
      , me = this
 | 
						|
      ;
 | 
						|
 | 
						|
 | 
						|
    me._wcurfile = file;
 | 
						|
    me._wCurFileCallback = cont;
 | 
						|
    me.emit('name', me._wcurpath, file, noop);
 | 
						|
 | 
						|
    statPath = me._wcurpath + path.sep + file;
 | 
						|
 | 
						|
    if (!me._wsync) {
 | 
						|
      // TODO how to remove this anony?
 | 
						|
      fs[me._wStat](statPath, function (err, stat) {
 | 
						|
        me._wLstatHandler(err, stat);
 | 
						|
      });
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    try {
 | 
						|
      me._wLstatHandler(null, fs[me._wStatSync](statPath));
 | 
						|
    } catch(e) {
 | 
						|
      me._wLstatHandler(e);
 | 
						|
    }
 | 
						|
  };
 | 
						|
  Walker.prototype._wOnEmitDone = function () {
 | 
						|
    var me = this
 | 
						|
      , dirs = []
 | 
						|
      ;
 | 
						|
 | 
						|
    me._wfnodegroups.directories.forEach(appendToDirs, dirs);
 | 
						|
    dirs.forEach(me._wJoinPath, me);
 | 
						|
    me._wqueue.push(me._wq = dirs);
 | 
						|
    me._wNext();
 | 
						|
  };
 | 
						|
  Walker.prototype._wPostFilesHandler = function () {
 | 
						|
    var me = this
 | 
						|
      ;
 | 
						|
 | 
						|
    if (me._wfnodegroups.errors.length) {
 | 
						|
      // TODO v3.0 (don't noop the next)
 | 
						|
      // .errors is an array of stats with { name: name, error: error }
 | 
						|
      me.emit('errors', me._wcurpath, me._wfnodegroups.errors, noop);
 | 
						|
    }
 | 
						|
    // XXX emitNodeTypes still needs refactor
 | 
						|
    TypeEmitter.emitNodeTypeGroups(me, me._wcurpath, me._wfnodegroups, me._wOnEmitDone, me);
 | 
						|
  };
 | 
						|
  Walker.prototype._wReadFiles = function () {
 | 
						|
    var me = this
 | 
						|
      ;
 | 
						|
 | 
						|
    if (!me._wcurfiles || 0 === me._wcurfiles.length) {
 | 
						|
      return me._wNext();
 | 
						|
    }
 | 
						|
 | 
						|
    // TODO could allow user to selectively stat
 | 
						|
    // and don't stat if there are no stat listeners
 | 
						|
    me.emit('names', me._wcurpath, me._wcurfiles, noop);
 | 
						|
 | 
						|
    if (me._wsync) {
 | 
						|
      me._wcurfiles.forEach(wFilesHandlerWrapper, me);
 | 
						|
      me._wPostFilesHandler();
 | 
						|
    } else {
 | 
						|
      forEachAsync(me._wcurfiles, me._wFilesHandler, me).then(me._wPostFilesHandler);
 | 
						|
    }
 | 
						|
  };
 | 
						|
  Walker.prototype._wReaddirHandler = function (err, files) {
 | 
						|
    var fnodeGroups = TypeEmitter.createNodeGroups()
 | 
						|
      , me = this
 | 
						|
      , parent
 | 
						|
      , child
 | 
						|
      ;
 | 
						|
 | 
						|
    me._wfnodegroups = fnodeGroups;
 | 
						|
    me._wcurfiles = files;
 | 
						|
 | 
						|
    // no error, great
 | 
						|
    if (!err) {
 | 
						|
      me._wReadFiles();
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    // TODO path.sep
 | 
						|
    me._wcurpath = me._wcurpath.replace(/\/$/, '');
 | 
						|
 | 
						|
    // error? not first run? => directory error
 | 
						|
    if (!me._wfirstrun) {
 | 
						|
      // TODO v3.0 (don't noop the next if there are listeners)
 | 
						|
      me.emit('directoryError', me._wcurpath, { error: err }, noop);
 | 
						|
      // TODO v3.0
 | 
						|
      //me.emit('directoryError', me._wcurpath.replace(/^(.*)\/.*$/, '$1'), { name: me._wcurpath.replace(/^.*\/(.*)/, '$1'), error: err }, noop);
 | 
						|
      me._wReadFiles();
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    // error? first run? => maybe a file, maybe a true error
 | 
						|
    me._wfirstrun = false;
 | 
						|
 | 
						|
    // readdir failed (might be a file), try a stat on the parent
 | 
						|
    parent = me._wcurpath.replace(/^(.*)\/.*$/, '$1');
 | 
						|
    fs[me._wStat](parent, function (e, stat) {
 | 
						|
 | 
						|
      if (stat) {
 | 
						|
        // success
 | 
						|
        // now try stat on this as a child of the parent directory
 | 
						|
        child = me._wcurpath.replace(/^.*\/(.*)$/, '$1');
 | 
						|
        me._wcurfiles = [child];
 | 
						|
        me._wcurpath = parent;
 | 
						|
      } else {
 | 
						|
        // TODO v3.0
 | 
						|
        //me.emit('directoryError', me._wcurpath.replace(/^(.*)\/.*$/, '$1'), { name: me._wcurpath.replace(/^.*\/(.*)/, '$1'), error: err }, noop);
 | 
						|
        // TODO v3.0 (don't noop the next)
 | 
						|
        // the original readdir error, not the parent stat error
 | 
						|
        me.emit('nodeError', me._wcurpath, { error: err }, noop);
 | 
						|
      }
 | 
						|
 | 
						|
      me._wReadFiles();
 | 
						|
    });
 | 
						|
  };
 | 
						|
  Walker.prototype._wFilter = function () {
 | 
						|
    var me = this
 | 
						|
      , exclude
 | 
						|
      ;
 | 
						|
 | 
						|
    // Stop directories that contain filter keywords
 | 
						|
    // from continuing through the walk process
 | 
						|
    exclude = me._wfilters.some(function (filter) {
 | 
						|
      if (me._wcurpath.match(filter)) {
 | 
						|
        return true;
 | 
						|
      }
 | 
						|
    });
 | 
						|
 | 
						|
    return exclude;
 | 
						|
  };
 | 
						|
  Walker.prototype._wWalkSync = function () {
 | 
						|
    //console.log('walkSync');
 | 
						|
    var err
 | 
						|
      , files
 | 
						|
      , me = this
 | 
						|
      ;
 | 
						|
 | 
						|
    try {
 | 
						|
      files = fs.readdirSync(me._wcurpath);
 | 
						|
    } catch(e) {
 | 
						|
      err = e;
 | 
						|
    }
 | 
						|
 | 
						|
    me._wReaddirHandler(err, files);
 | 
						|
  };
 | 
						|
  Walker.prototype._wWalkAsync = function () {
 | 
						|
    //console.log('walkAsync');
 | 
						|
    var me = this
 | 
						|
      ;
 | 
						|
 | 
						|
    // TODO how to remove this anony?
 | 
						|
    fs.readdir(me._wcurpath, function (err, files) {
 | 
						|
      me._wReaddirHandler(err, files);
 | 
						|
    });
 | 
						|
  };
 | 
						|
  Walker.prototype._wNext = function () {
 | 
						|
    var me = this
 | 
						|
      ;
 | 
						|
 | 
						|
    if (me._paused) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    if (me._wq.length) {
 | 
						|
      me._wcurpath = me._wq.pop();
 | 
						|
      while (me._wq.length && me._wFilter()) {
 | 
						|
        me._wcurpath = me._wq.pop();
 | 
						|
      }
 | 
						|
      if (me._wcurpath && !me._wFilter()) {
 | 
						|
        me._wWalk();
 | 
						|
      } else {
 | 
						|
        me._wNext();
 | 
						|
      }
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    me._wqueue.length -= 1;
 | 
						|
    if (me._wqueue.length) {
 | 
						|
      me._wq = me._wqueue[me._wqueue.length - 1];
 | 
						|
      return me._wNext();
 | 
						|
    }
 | 
						|
 | 
						|
    // To not break compatibility
 | 
						|
    //process.nextTick(function () {
 | 
						|
      me.emit('end');
 | 
						|
    //});
 | 
						|
  };
 | 
						|
  Walker.prototype._wJoinPath = function (v, i, o) {
 | 
						|
    var me = this
 | 
						|
      ;
 | 
						|
 | 
						|
    o[i] = [me._wcurpath, path.sep, v].join('');
 | 
						|
  };
 | 
						|
  Walker.prototype.pause = function () {
 | 
						|
    this._paused = true;
 | 
						|
  };
 | 
						|
  Walker.prototype.resume = function () {
 | 
						|
    this._paused = false;
 | 
						|
    this._wNext();
 | 
						|
  };
 | 
						|
 | 
						|
  exports.walk = function (path, opts) {
 | 
						|
    return new Walker(path, opts, false);
 | 
						|
  };
 | 
						|
 | 
						|
  exports.walkSync = function (path, opts) {
 | 
						|
    return new Walker(path, opts, true);
 | 
						|
  };
 | 
						|
}());
 |