file.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. var path = require('path');
  2. var fs = require('fs');
  3. var assert = require("assert");
  4. // file.mkdirs
  5. //
  6. // Given a path to a directory, create it, and all the intermediate directories
  7. // as well
  8. //
  9. // @path: the path to create
  10. // @mode: the file mode to create the directory with:
  11. // ex: file.mkdirs("/tmp/dir", 755, function () {})
  12. // @callback: called when finished.
  13. exports.mkdirs = function (_path, mode, callback) {
  14. _path = exports.path.abspath(_path);
  15. var dirs = _path.split(path.sep);
  16. var walker = [dirs.shift()];
  17. // walk
  18. // @ds: A list of directory names
  19. // @acc: An accumulator of walked dirs
  20. // @m: The mode
  21. // @cb: The callback
  22. var walk = function (ds, acc, m, cb) {
  23. if (ds.length > 0) {
  24. var d = ds.shift();
  25. acc.push(d);
  26. var dir = acc.join(path.sep);
  27. // look for dir on the fs, if it doesn't exist then create it, and
  28. // continue our walk, otherwise if it's a file, we have a name
  29. // collision, so exit.
  30. fs.stat(dir, function (err, stat) {
  31. // if the directory doesn't exist then create it
  32. if (err) {
  33. // 2 means it's wasn't there
  34. if (err.errno == 2 || err.errno == 34) {
  35. fs.mkdir(dir, m, function (erro) {
  36. if (erro && erro.errno != 17 && erro.errno != 34) {
  37. return cb(erro);
  38. } else {
  39. return walk(ds, acc, m, cb);
  40. }
  41. });
  42. } else {
  43. return cb(err);
  44. }
  45. } else {
  46. if (stat.isDirectory()) {
  47. return walk(ds, acc, m, cb);
  48. } else {
  49. return cb(new Error("Failed to mkdir " + dir + ": File exists\n"));
  50. }
  51. }
  52. });
  53. } else {
  54. return cb();
  55. }
  56. };
  57. return walk(dirs, walker, mode, callback);
  58. };
  59. // file.mkdirsSync
  60. //
  61. // Synchronus version of file.mkdirs
  62. //
  63. // Given a path to a directory, create it, and all the intermediate directories
  64. // as well
  65. //
  66. // @path: the path to create
  67. // @mode: the file mode to create the directory with:
  68. // ex: file.mkdirs("/tmp/dir", 755, function () {})
  69. exports.mkdirsSync = function (_path, mode) {
  70. if (_path[0] !== path.sep) {
  71. _path = path.join(process.cwd(), _path)
  72. }
  73. var dirs = _path.split(path.sep);
  74. var walker = [dirs.shift()];
  75. dirs.reduce(function (acc, d) {
  76. acc.push(d);
  77. var dir = acc.join(path.sep);
  78. try {
  79. var stat = fs.statSync(dir);
  80. if (!stat.isDirectory()) {
  81. throw "Failed to mkdir " + dir + ": File exists";
  82. }
  83. } catch (err) {
  84. fs.mkdirSync(dir, mode);
  85. }
  86. return acc;
  87. }, walker);
  88. };
  89. // file.walk
  90. //
  91. // Given a path to a directory, walk the fs below that directory
  92. //
  93. // @start: the path to startat
  94. // @callback: called for each new directory we enter
  95. // ex: file.walk("/tmp", function(error, path, dirs, name) {})
  96. //
  97. // path is the current directory we're in
  98. // dirs is the list of directories below it
  99. // names is the list of files in it
  100. //
  101. exports.walk = function (start, callback) {
  102. fs.lstat(start, function (err, stat) {
  103. if (err) { return callback(err) }
  104. if (stat.isDirectory()) {
  105. fs.readdir(start, function (err, files) {
  106. var coll = files.reduce(function (acc, i) {
  107. var abspath = path.join(start, i);
  108. if (fs.statSync(abspath).isDirectory()) {
  109. exports.walk(abspath, callback);
  110. acc.dirs.push(abspath);
  111. } else {
  112. acc.names.push(abspath);
  113. }
  114. return acc;
  115. }, {"names": [], "dirs": []});
  116. return callback(null, start, coll.dirs, coll.names);
  117. });
  118. } else {
  119. return callback(new Error("path: " + start + " is not a directory"));
  120. }
  121. });
  122. };
  123. // file.walkSync
  124. //
  125. // Synchronus version of file.walk
  126. //
  127. // Given a path to a directory, walk the fs below that directory
  128. //
  129. // @start: the path to startat
  130. // @callback: called for each new directory we enter
  131. // ex: file.walk("/tmp", function(error, path, dirs, name) {})
  132. //
  133. // path is the current directory we're in
  134. // dirs is the list of directories below it
  135. // names is the list of files in it
  136. //
  137. exports.walkSync = function (start, callback) {
  138. var stat = fs.statSync(start);
  139. if (stat.isDirectory()) {
  140. var filenames = fs.readdirSync(start);
  141. var coll = filenames.reduce(function (acc, name) {
  142. var abspath = path.join(start, name);
  143. if (fs.statSync(abspath).isDirectory()) {
  144. acc.dirs.push(name);
  145. } else {
  146. acc.names.push(name);
  147. }
  148. return acc;
  149. }, {"names": [], "dirs": []});
  150. callback(start, coll.dirs, coll.names);
  151. coll.dirs.forEach(function (d) {
  152. var abspath = path.join(start, d);
  153. exports.walkSync(abspath, callback);
  154. });
  155. } else {
  156. throw new Error("path: " + start + " is not a directory");
  157. }
  158. };
  159. exports.path = {};
  160. exports.path.abspath = function (to) {
  161. var from;
  162. switch (to.charAt(0)) {
  163. case "~": from = process.env.HOME; to = to.substr(1); break
  164. case path.sep: from = ""; break
  165. default : from = process.cwd(); break
  166. }
  167. return path.join(from, to);
  168. }
  169. exports.path.relativePath = function (base, compare) {
  170. base = base.split(path.sep);
  171. compare = compare.split(path.sep);
  172. if (base[0] == "") {
  173. base.shift();
  174. }
  175. if (compare[0] == "") {
  176. compare.shift();
  177. }
  178. var l = compare.length;
  179. for (var i = 0; i < l; i++) {
  180. if (!base[i] || (base[i] != compare[i])) {
  181. return compare.slice(i).join(path.sep);
  182. }
  183. }
  184. return ""
  185. };
  186. exports.path.join = function (head, tail) {
  187. if (head == "") {
  188. return tail;
  189. } else {
  190. return path.join(head, tail);
  191. }
  192. };