copy.js 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. /*
  2. * grunt-contrib-copy
  3. * http://gruntjs.com/
  4. *
  5. * Copyright (c) 2016 Chris Talkington, contributors
  6. * Licensed under the MIT license.
  7. * https://github.com/gruntjs/grunt-contrib-copy/blob/master/LICENSE-MIT
  8. */
  9. 'use strict';
  10. module.exports = function(grunt) {
  11. var path = require('path');
  12. var fs = require('fs');
  13. var chalk = require('chalk');
  14. var fileSyncCmp = require('file-sync-cmp');
  15. var isWindows = process.platform === 'win32';
  16. grunt.registerMultiTask('copy', 'Copy files.', function() {
  17. var options = this.options({
  18. encoding: grunt.file.defaultEncoding,
  19. // processContent/processContentExclude deprecated renamed to process/noProcess
  20. processContent: false,
  21. processContentExclude: [],
  22. timestamp: false,
  23. mode: false
  24. });
  25. var copyOptions = {
  26. encoding: options.encoding,
  27. process: options.process || options.processContent,
  28. noProcess: options.noProcess || options.processContentExclude
  29. };
  30. var detectDestType = function(dest) {
  31. if (grunt.util._.endsWith(dest, '/')) {
  32. return 'directory';
  33. } else {
  34. return 'file';
  35. }
  36. };
  37. var unixifyPath = function(filepath) {
  38. if (isWindows) {
  39. return filepath.replace(/\\/g, '/');
  40. } else {
  41. return filepath;
  42. }
  43. };
  44. var syncTimestamp = function (src, dest) {
  45. var stat = fs.lstatSync(src);
  46. if (path.basename(src) !== path.basename(dest)) {
  47. return;
  48. }
  49. if (stat.isFile() && !fileSyncCmp.equalFiles(src, dest)) {
  50. return;
  51. }
  52. var fd = fs.openSync(dest, isWindows ? 'r+' : 'r');
  53. fs.futimesSync(fd, stat.atime, stat.mtime);
  54. fs.closeSync(fd);
  55. };
  56. var isExpandedPair;
  57. var dirs = {};
  58. var tally = {
  59. dirs: 0,
  60. files: 0
  61. };
  62. this.files.forEach(function(filePair) {
  63. isExpandedPair = filePair.orig.expand || false;
  64. filePair.src.forEach(function(src) {
  65. src = unixifyPath(src);
  66. var dest = unixifyPath(filePair.dest);
  67. if (detectDestType(dest) === 'directory') {
  68. dest = isExpandedPair ? dest : path.join(dest, src);
  69. }
  70. if (grunt.file.isDir(src)) {
  71. grunt.verbose.writeln('Creating ' + chalk.cyan(dest));
  72. grunt.file.mkdir(dest);
  73. if (options.mode !== false) {
  74. fs.chmodSync(dest, (options.mode === true) ? fs.lstatSync(src).mode : options.mode);
  75. }
  76. if (options.timestamp) {
  77. dirs[dest] = src;
  78. }
  79. tally.dirs++;
  80. } else {
  81. grunt.verbose.writeln('Copying ' + chalk.cyan(src) + ' -> ' + chalk.cyan(dest));
  82. grunt.file.copy(src, dest, copyOptions);
  83. syncTimestamp(src, dest);
  84. if (options.mode !== false) {
  85. fs.chmodSync(dest, (options.mode === true) ? fs.lstatSync(src).mode : options.mode);
  86. }
  87. tally.files++;
  88. }
  89. });
  90. });
  91. if (options.timestamp) {
  92. Object.keys(dirs).sort(function (a, b) {
  93. return b.length - a.length;
  94. }).forEach(function (dest) {
  95. syncTimestamp(dirs[dest], dest);
  96. });
  97. }
  98. if (tally.dirs) {
  99. grunt.log.write('Created ' + chalk.cyan(tally.dirs.toString()) + (tally.dirs === 1 ? ' directory' : ' directories'));
  100. }
  101. if (tally.files) {
  102. grunt.log.write((tally.dirs ? ', copied ' : 'Copied ') + chalk.cyan(tally.files.toString()) + (tally.files === 1 ? ' file' : ' files'));
  103. }
  104. grunt.log.writeln();
  105. });
  106. };