gulp-copy.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. const path = require('path');
  2. const fs = require('fs');
  3. const through = require('through2');
  4. const PluginError = require('plugin-error');
  5. const separator = path.sep;
  6. /**
  7. * gulp copy method
  8. * @param {string} destination
  9. * @param {object} opts
  10. * @returns {object}
  11. */
  12. function gulpCopy(destination, opts) {
  13. const throughOptions = { objectMode: true };
  14. // Make sure a destination was verified
  15. if (typeof destination !== 'string') {
  16. throw new PluginError('gulp-copy', 'No valid destination specified');
  17. }
  18. // Default options
  19. if (opts === undefined) {
  20. opts = opts || {};
  21. } else if (typeof opts !== 'object' || opts === null) {
  22. throw new PluginError('gulp-copy', 'No valid options specified');
  23. }
  24. return through(throughOptions, transform);
  25. /**
  26. * Transform method, copies the file to its new destination
  27. * @param {object} file
  28. * @param {string} encoding
  29. * @param {function} cb
  30. */
  31. function transform(file, encoding, cb) {
  32. let rel = null;
  33. let fileDestination = null;
  34. if (file.isStream()) {
  35. cb(new PluginError('gulp-copy', 'Streaming not supported'));
  36. }
  37. if (file.isNull()) {
  38. cb(null, file);
  39. } else {
  40. rel = path.relative(file.cwd, file.path).replace(/\\/g, separator);
  41. // Strip path prefixes
  42. if (opts.prefix) {
  43. let p = opts.prefix;
  44. while (p-- > 0) {
  45. rel = rel.substring(rel.indexOf(separator) + 1);
  46. }
  47. }
  48. fileDestination = path.join(destination, rel);
  49. // Make sure destination exists
  50. if (!doesPathExist(fileDestination)) {
  51. createDestination(fileDestination.substr(0, fileDestination.lastIndexOf(separator)));
  52. }
  53. // Copy the file
  54. copyFile(file.path, fileDestination, function copyFileCallback(error) {
  55. if (error) {
  56. throw new PluginError('gulp-copy', `Could not copy file <${file.path}>: ${error.message}`);
  57. }
  58. // Update path for file so this path is used later on
  59. file.path = fileDestination;
  60. cb(null, file);
  61. });
  62. }
  63. }
  64. }
  65. /**
  66. * Recursively creates the path
  67. * @param {string} destination
  68. */
  69. function createDestination(destination) {
  70. const folders = destination.split(separator);
  71. const pathParts = [];
  72. const l = folders.length;
  73. // for absolute paths
  74. if (folders[0] === '') {
  75. pathParts.push(separator);
  76. folders.shift();
  77. }
  78. for (let i = 0; i < l; i++) {
  79. pathParts.push(folders[i]);
  80. if (folders[i] !== '' && !doesPathExist(pathParts.join(separator))) {
  81. try {
  82. fs.mkdirSync(pathParts.join(separator));
  83. } catch (error) {
  84. throw new PluginError('gulp-copy', `Could not create destination <${destination}>: ${error.message}`);
  85. }
  86. }
  87. }
  88. }
  89. /**
  90. * Check if the path exists
  91. * @param path
  92. * @returns {boolean}
  93. */
  94. function doesPathExist(pathToVerify) {
  95. let pathExists = true;
  96. try {
  97. fs.accessSync(pathToVerify);
  98. } catch (error) {
  99. pathExists = false;
  100. }
  101. return pathExists;
  102. }
  103. /**
  104. * Copy a file to its new destination
  105. * @param {string} source
  106. * @param {string} target
  107. * @param {function} copyCallback
  108. */
  109. function copyFile(source, target, copyCallback) {
  110. const readStream = fs.createReadStream(source);
  111. const writeStream = fs.createWriteStream(target);
  112. let done = false;
  113. readStream.on('error', copyDone);
  114. writeStream.on('error', copyDone);
  115. writeStream.on('close', function onWriteCb() {
  116. copyDone(null);
  117. });
  118. readStream.pipe(writeStream);
  119. /**
  120. * Finish copying. Reports error when needed
  121. * @param [error] optional error
  122. */
  123. function copyDone(error) {
  124. if (!done) {
  125. done = true;
  126. copyCallback(error);
  127. }
  128. }
  129. }
  130. module.exports = gulpCopy;