blob: bdb476cdc50d0cf5a0bdf40cbe22f6d43ec3972c [file] [log] [blame]
Leo Repp58b9f112021-11-22 11:57:47 +01001/*
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
10'use strict';
11
12module.exports = function(grunt) {
13 var path = require('path');
14 var fs = require('fs');
15 var chalk = require('chalk');
16 var fileSyncCmp = require('file-sync-cmp');
17 var isWindows = process.platform === 'win32';
18
19 grunt.registerMultiTask('copy', 'Copy files.', function() {
20
21 var options = this.options({
22 encoding: grunt.file.defaultEncoding,
23 // processContent/processContentExclude deprecated renamed to process/noProcess
24 processContent: false,
25 processContentExclude: [],
26 timestamp: false,
27 mode: false
28 });
29
30 var copyOptions = {
31 encoding: options.encoding,
32 process: options.process || options.processContent,
33 noProcess: options.noProcess || options.processContentExclude
34 };
35
36 var detectDestType = function(dest) {
37 if (grunt.util._.endsWith(dest, '/')) {
38 return 'directory';
39 } else {
40 return 'file';
41 }
42 };
43
44 var unixifyPath = function(filepath) {
45 if (isWindows) {
46 return filepath.replace(/\\/g, '/');
47 } else {
48 return filepath;
49 }
50 };
51
52 var syncTimestamp = function (src, dest) {
53 var stat = fs.lstatSync(src);
54 if (path.basename(src) !== path.basename(dest)) {
55 return;
56 }
57
58 if (stat.isFile() && !fileSyncCmp.equalFiles(src, dest)) {
59 return;
60 }
61
62 var fd = fs.openSync(dest, isWindows ? 'r+' : 'r');
63 fs.futimesSync(fd, stat.atime, stat.mtime);
64 fs.closeSync(fd);
65 };
66
67 var isExpandedPair;
68 var dirs = {};
69 var tally = {
70 dirs: 0,
71 files: 0
72 };
73
74 this.files.forEach(function(filePair) {
75 isExpandedPair = filePair.orig.expand || false;
76
77 filePair.src.forEach(function(src) {
78 src = unixifyPath(src);
79 var dest = unixifyPath(filePair.dest);
80
81 if (detectDestType(dest) === 'directory') {
82 dest = isExpandedPair ? dest : path.join(dest, src);
83 }
84
85 if (grunt.file.isDir(src)) {
86 grunt.verbose.writeln('Creating ' + chalk.cyan(dest));
87 grunt.file.mkdir(dest);
88 if (options.mode !== false) {
89 fs.chmodSync(dest, (options.mode === true) ? fs.lstatSync(src).mode : options.mode);
90 }
91
92 if (options.timestamp) {
93 dirs[dest] = src;
94 }
95
96 tally.dirs++;
97 } else {
98 grunt.verbose.writeln('Copying ' + chalk.cyan(src) + ' -> ' + chalk.cyan(dest));
99 grunt.file.copy(src, dest, copyOptions);
100 syncTimestamp(src, dest);
101 if (options.mode !== false) {
102 fs.chmodSync(dest, (options.mode === true) ? fs.lstatSync(src).mode : options.mode);
103 }
104 tally.files++;
105 }
106 });
107 });
108
109 if (options.timestamp) {
110 Object.keys(dirs).sort(function (a, b) {
111 return b.length - a.length;
112 }).forEach(function (dest) {
113 syncTimestamp(dirs[dest], dest);
114 });
115 }
116
117 if (tally.dirs) {
118 grunt.log.write('Created ' + chalk.cyan(tally.dirs.toString()) + (tally.dirs === 1 ? ' directory' : ' directories'));
119 }
120
121 if (tally.files) {
122 grunt.log.write((tally.dirs ? ', copied ' : 'Copied ') + chalk.cyan(tally.files.toString()) + (tally.files === 1 ? ' file' : ' files'));
123 }
124
125 grunt.log.writeln();
126 });
127
128};