index.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. 'use strict';
  2. var path = require('path');
  3. var fs = require('fs');
  4. var glob = require('glob');
  5. var mkdirp = require('mkdirp');
  6. var untildify = require('untildify');
  7. var through = require('through2').obj;
  8. var noms = require('noms').obj;
  9. function toStream(array) {
  10. var length = array.length;
  11. var i = 0;
  12. return noms(function (done) {
  13. if (i >= length) {
  14. this.push(null);
  15. }
  16. this.push(array[i++]);
  17. done();
  18. });
  19. }
  20. function depth(string) {
  21. return path.normalize(string).split(path.sep).length - 1;
  22. }
  23. function dealWith(inPath, up) {
  24. if (!up) {
  25. return inPath;
  26. }
  27. if (up === true) {
  28. return path.basename(inPath);
  29. }
  30. if (depth(inPath) < up) {
  31. throw new Error('cant go up that far');
  32. }
  33. return path.join.apply(path, path.normalize(inPath).split(path.sep).slice(up));
  34. }
  35. var copyFile = _copyFile;
  36. function _copyFile (src, dst, opts, callback) {
  37. fs.createReadStream(src)
  38. .pipe(fs.createWriteStream(dst, {
  39. mode: opts.mode
  40. }))
  41. .once('error', callback)
  42. .once('finish', function () {
  43. fs.chmod(dst, opts.mode, function (err) {
  44. callback(err);
  45. })
  46. })
  47. }
  48. if (fs.copyFile) {
  49. copyFile = function (src, dst, opts, callback) {
  50. fs.copyFile(src, dst, callback);
  51. }
  52. }
  53. function makeDebug(config) {
  54. if (config.verbose) {
  55. return function (thing) {
  56. console.log(thing);
  57. }
  58. }
  59. return function () {}
  60. }
  61. module.exports = copyFiles;
  62. function copyFiles(args, config, callback) {
  63. if (typeof config === 'function') {
  64. callback = config;
  65. config = {
  66. up:0
  67. };
  68. }
  69. if (typeof config !== 'object' && config) {
  70. config = {
  71. up: config
  72. };
  73. }
  74. var debug = makeDebug(config);
  75. var copied = false;
  76. var opts = config.up || 0;
  77. var soft = config.soft;
  78. if (typeof callback !== 'function') {
  79. throw new Error('callback is not optional');
  80. }
  81. var input = args.slice();
  82. var outDir = input.pop();
  83. var globOpts = {};
  84. if (config.exclude) {
  85. globOpts.ignore = config.exclude;
  86. }
  87. if (config.all) {
  88. globOpts.dot = true;
  89. }
  90. if (config.follow) {
  91. globOpts.follow = true;
  92. }
  93. outDir = outDir.startsWith('~') ? untildify(outDir) : outDir;
  94. toStream(input.map(function(srcP) {return srcP.startsWith('~') ? untildify(srcP) : srcP;}))
  95. .pipe(through(function (pathName, _, next) {
  96. var self = this;
  97. glob(pathName, globOpts, function (err, paths) {
  98. if (err) {
  99. return next(err);
  100. }
  101. paths.forEach(function (unglobbedPath) {
  102. debug(`unglobed path: ${unglobbedPath}`);
  103. self.push(unglobbedPath);
  104. });
  105. next();
  106. });
  107. }))
  108. .on('error', callback)
  109. .pipe(through(function (pathName, _, next) {
  110. fs.stat(pathName, function (err, pathStat) {
  111. if (err) {
  112. return next(err);
  113. }
  114. var outName = path.join(outDir, dealWith(pathName, opts));
  115. function done(){
  116. mkdirp(path.dirname(outName)).then(()=>{
  117. next(null, {
  118. pathName: pathName,
  119. pathStat: pathStat
  120. });
  121. }, next);
  122. }
  123. if (pathStat.isDirectory()) {
  124. debug(`skipping, is directory: ${pathName}`)
  125. return next();
  126. }
  127. if (!pathStat.isFile()) {
  128. return next(new Error('how can it be neither file nor folder?'))
  129. }
  130. if (!soft) {
  131. return done();
  132. }
  133. fs.stat(outName, function(err){
  134. if(!err){
  135. //file exists
  136. return next()
  137. }
  138. if (err.code === 'ENOENT') {
  139. //file does not exist
  140. return done();
  141. }
  142. // other error
  143. return next(err)
  144. })
  145. });
  146. }))
  147. .on('error', callback)
  148. .pipe(through(function (obj, _, next) {
  149. if (!copied) {
  150. copied = true;
  151. }
  152. var pathName = obj.pathName;
  153. var pathStat = obj.pathStat;
  154. var outName = path.join(outDir, dealWith(pathName, opts));
  155. debug(`copy from: ${pathName}`)
  156. debug(`copy to: ${outName}`)
  157. copyFile(pathName, outName, pathStat, next)
  158. }))
  159. .on('error', callback)
  160. .on('finish', function () {
  161. if (config.error && !copied) {
  162. return callback(new Error('nothing coppied'));
  163. }
  164. callback();
  165. });
  166. }