copy.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. var async = require("async");
  2. var fs = require("fs");
  3. var path = require("path");
  4. // cursively make dir
  5. function mkdirs(p, mode, f, made) {
  6. if (typeof mode === 'function' || mode === undefined) {
  7. f = mode;
  8. mode = 0777 & (~process.umask());
  9. }
  10. if (!made)
  11. made = null;
  12. var cb = f || function () {};
  13. if (typeof mode === 'string')
  14. mode = parseInt(mode, 8);
  15. p = path.resolve(p);
  16. fs.mkdir(p, mode, function (er) {
  17. if (!er) {
  18. made = made || p;
  19. return cb(null, made);
  20. }
  21. switch (er.code) {
  22. case 'ENOENT':
  23. mkdirs(path.dirname(p), mode, function (er, made) {
  24. if (er) {
  25. cb(er, made);
  26. } else {
  27. mkdirs(p, mode, cb, made);
  28. }
  29. });
  30. break;
  31. // In the case of any other error, just see if there's a dir
  32. // there already. If so, then hooray! If not, then something
  33. // is borked.
  34. default:
  35. fs.stat(p, function (er2, stat) {
  36. // if the stat fails, then that's super weird.
  37. // let the original error be the failure reason.
  38. if (er2 || !stat.isDirectory()) {
  39. cb(er, made);
  40. } else {
  41. cb(null, made)
  42. };
  43. });
  44. break;
  45. }
  46. });
  47. }
  48. // single file copy
  49. function copyFile(file, toDir, cb) {
  50. async.waterfall([
  51. function (callback) {
  52. fs.exists(toDir, function (exists) {
  53. if (exists) {
  54. callback(null, false);
  55. } else {
  56. callback(null, true);
  57. }
  58. });
  59. }, function (need, callback) {
  60. if (need) {
  61. mkdirs(path.dirname(toDir), callback);
  62. } else {
  63. callback(null, true);
  64. }
  65. }, function (p, callback) {
  66. console.log(file);
  67. var reads = fs.createReadStream(file);
  68. var writes = fs.createWriteStream(path.join(path.dirname(toDir), path.basename(file)));
  69. reads.pipe(writes);
  70. //don't forget close the when all the data are read
  71. reads.on("end", function () {
  72. writes.end();
  73. callback(null);
  74. });
  75. reads.on("error", function (err) {
  76. console.log("error occur in reads");
  77. callback(true, err);
  78. });
  79. }
  80. ], cb);
  81. }
  82. // cursively count the files that need to be copied
  83. function _ccoutTask(from, to, cbw) {
  84. async.waterfall([
  85. function (callback) {
  86. fs.stat(from, callback);
  87. },
  88. function (stats, callback) {
  89. if (stats.isFile()) {
  90. cbw.addFile(from, to);
  91. callback(null, []);
  92. } else if (stats.isDirectory()) {
  93. fs.readdir(from, callback);
  94. }
  95. },
  96. function (files, callback) {
  97. if (files.length) {
  98. for (var i = 0; i < files.length; i++) {
  99. _ccoutTask(path.join(from, files[i]), path.join(to, files[i]), cbw.increase());
  100. }
  101. }
  102. callback(null);
  103. }
  104. ], cbw);
  105. }
  106. // wrap the callback before counting
  107. function ccoutTask(from, to, cb) {
  108. var files = [];
  109. var count = 1;
  110. function wrapper(err) {
  111. count--;
  112. if (err || count <= 0) {
  113. cb(err, files)
  114. }
  115. }
  116. wrapper.increase = function () {
  117. count++;
  118. return wrapper;
  119. }
  120. wrapper.addFile = function (file, dir) {
  121. files.push({
  122. file : file,
  123. dir : dir
  124. });
  125. }
  126. _ccoutTask(from, to, wrapper);
  127. }
  128. function copyDir(from, to, cb) {
  129. if(!cb){
  130. cb=function(){};
  131. }
  132. async.waterfall([
  133. function (callback) {
  134. fs.exists(from, function (exists) {
  135. if (exists) {
  136. callback(null, true);
  137. } else {
  138. console.log(from + " not exists");
  139. callback(true);
  140. }
  141. });
  142. },
  143. function (exists, callback) {
  144. fs.stat(from, callback);
  145. },
  146. function (stats, callback) {
  147. if (stats.isFile()) {
  148. // one file copy
  149. copyFile(from, to, function (err) {
  150. if (err) {
  151. // break the waterfall
  152. callback(true);
  153. } else {
  154. callback(null, []);
  155. }
  156. });
  157. } else if (stats.isDirectory()) {
  158. ccoutTask(from, to, callback);
  159. }
  160. },
  161. function (files, callback) {
  162. // prevent reaching to max file open limit
  163. async.mapLimit(files, 10, function (f, cb) {
  164. copyFile(f.file, f.dir, cb);
  165. }, callback);
  166. }
  167. ], cb);
  168. }
  169. module.exports = {
  170. copyDir: copyDir,
  171. }