Skip to content

Instantly share code, notes, and snippets.

@tim-smart
Created February 4, 2010 09:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tim-smart/294488 to your computer and use it in GitHub Desktop.
Save tim-smart/294488 to your computer and use it in GitHub Desktop.
var Walker = require('./walker').Walker;
var walker = new Walker();
walker.walk('/home/test/', function(structure) {
// structure now contains dir tree
// The directory / filename
structure.name;
// The directory / file path relative to given path
structure.path;
// Contains a array of file objects
structure.files;
// Contains a array of directorie objects
structure.directories;
// Whether it is a directory true/false
structure.isDirectory();
// Gets both file and directory objects
structure.getAll();
// File and directory objects have the exact same methods
structure.files[1].path;
// Export to JSON object
structure.exportToJson();
});
// Directory tree walker utility
var path = require('path'),
posix = require('posix'),
events = require('events'),
NAME_RE = /(?:.*\/)?(.*)/;
// Represents a file / folder
var FileFolder = function(options) {
this.name = options.name;
this.path = options.path;
this.dir = options.dir;
this.files = [];
this.directories = [];
};
FileFolder.prototype = {
append: function(filefolder) {
if (true === filefolder.dir)
this.directories.push(filefolder);
else
this.files.push(filefolder);
return filefolder;
},
getAll: function() {
var temp = Array.prototype.slice.call(this.files);
temp.push.apply(temp, this.directories);
return temp;
},
exportToJson: function() {
return this._recurse(this.getAll());
},
_recurse: function(items) {
var ret = {};
for (var i = 0, ff; ff = items[i]; i++) {
if (true === ff.isDirectory()) {
ret[ff.name] = this._recurse(ff.getAll());
} else {
ret[ff.name] = null;
}
}
return ret;
},
isDirectory: function() {
return this.dir || false;
}
};
// Walker prototype
var Walker = function() {
this._counter = 0;
this.structure = {};
};
exports.Walker = Walker;
Walker.prototype = {
_listDir: function (pathname, callback) {
var p = new events.Promise(),
ls = process.createChildProcess("ls", [pathname]);
ls.addListener("output", function (data) {
if (data) {
var files = [];
data.split('\n').forEach(function(f) {
if (f)
files.push(f);
});
callback(files);
}
});
},
walk: function (pathname, callback, base) {
var self = this,
dir = false,
abspath = "",
name = "";
if ("object" !== typeof base) {
if ("/" === pathname[pathname.length - 1])
pathname = pathname.slice(0, -1);
self.structure = base = new FileFolder({
"name": pathname.match(NAME_RE)[1],
"path": pathname,
"dir": true
});
}
this._listDir(pathname, function(files) {
files.forEach(function(f) {
self._counter++;
var abspath = path.join(pathname, f);
posix.stat(abspath).addCallback(function(stat) {
self._counter--;
name = abspath.match(NAME_RE)[1];
if (stat.isDirectory()) {
dir = true;
self.walk.call(self, abspath, callback, base.append(new FileFolder({
"name": name,
"path": abspath,
"dir": true
})));
} else {
base.append(new FileFolder({
"name": name,
"path": abspath,
"dir": false
}));
}
if (false === dir && 0 >= self._counter) {
callback.call(self, self.structure);
self.structure = {};
}
});
});
});
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment