@@ -7,12 +7,14 @@ const { pathExists } = require('../path-exists')
7
7
const { utimesMillisAsync } = require ( '../util/utimes' )
8
8
const stat = require ( '../util/stat' )
9
9
10
- async function copy ( src , dest , opts ) {
10
+ async function copy ( src , dest , opts = { } ) {
11
11
if ( typeof opts === 'function' ) {
12
12
opts = { filter : opts }
13
13
}
14
14
15
- opts = opts || { }
15
+ opts = typeof opts === 'function'
16
+ ? { filter : opts }
17
+ : opts
16
18
17
19
opts . clobber = 'clobber' in opts ? ! ! opts . clobber : true // default to true for now
18
20
opts . overwrite = 'overwrite' in opts ? ! ! opts . overwrite : opts . clobber // overwrite falls back to clobber
@@ -37,27 +39,24 @@ async function copy (src, dest, opts) {
37
39
return checkParentDir ( destStat , src , dest , opts )
38
40
}
39
41
40
- async function checkParentDir ( destStat , src , dest , opts ) {
42
+ async function checkParentDir ( destStat , src , dest , opts ) {
41
43
const destParent = path . dirname ( dest )
42
44
43
45
const dirExists = await pathExists ( destParent )
44
46
45
- if ( dirExists ) return getStats ( destStat , src , dest , opts )
46
-
47
- const parentDirExists = await pathExists ( destParent )
48
- if ( parentDirExists ) return getStats ( destStat , src , dest , opts )
49
-
50
- await mkdirs ( destParent )
47
+ if ( ! dirExists ) {
48
+ await mkdirs ( destParent )
49
+ }
51
50
52
51
return getStats ( destStat , src , dest , opts )
53
52
}
54
53
55
- async function runFilter ( src , dest , opts ) {
54
+ async function runFilter ( src , dest , opts ) {
56
55
if ( ! opts . filter ) return true
57
56
return opts . filter ( src , dest )
58
57
}
59
58
60
- async function getStats ( destStat , src , dest , opts ) {
59
+ async function getStats ( destStat , src , dest , opts ) {
61
60
const statFn = opts . dereference ? fs . stat : fs . lstat
62
61
const srcStat = await statFn ( src )
63
62
@@ -75,12 +74,9 @@ async function getStats (destStat, src, dest, opts) {
75
74
throw new Error ( `Unknown file: ${ src } ` )
76
75
}
77
76
78
- function onFile ( srcStat , destStat , src , dest , opts ) {
77
+ async function onFile ( srcStat , destStat , src , dest , opts ) {
79
78
if ( ! destStat ) return copyFile ( srcStat , src , dest , opts )
80
- return mayCopyFile ( srcStat , src , dest , opts )
81
- }
82
79
83
- async function mayCopyFile ( srcStat , src , dest , opts ) {
84
80
if ( opts . overwrite ) {
85
81
await fs . unlink ( dest )
86
82
return copyFile ( srcStat , src , dest , opts )
@@ -90,75 +86,68 @@ async function mayCopyFile (srcStat, src, dest, opts) {
90
86
}
91
87
}
92
88
93
- async function copyFile ( srcStat , src , dest , opts ) {
89
+ async function copyFile ( srcStat , src , dest , opts ) {
94
90
await fs . copyFile ( src , dest )
95
91
if ( opts . preserveTimestamps ) {
96
92
return handleTimestampsAndMode ( srcStat . mode , src , dest )
97
93
}
98
94
return setDestMode ( dest , srcStat . mode )
99
95
}
100
96
101
- async function handleTimestampsAndMode ( srcMode , src , dest ) {
97
+ async function handleTimestampsAndMode ( srcMode , src , dest ) {
102
98
// Make sure the file is writable before setting the timestamp
103
99
// otherwise open fails with EPERM when invoked with 'r+'
104
100
// (through utimes call)
105
101
if ( fileIsNotWritable ( srcMode ) ) {
106
102
await makeFileWritable ( dest , srcMode )
107
- return setDestTimestampsAndMode ( srcMode , src , dest )
108
103
}
109
104
return setDestTimestampsAndMode ( srcMode , src , dest )
110
105
}
111
106
112
- function fileIsNotWritable ( srcMode ) {
107
+ function fileIsNotWritable ( srcMode ) {
113
108
return ( srcMode & 0o200 ) === 0
114
109
}
115
110
116
- function makeFileWritable ( dest , srcMode ) {
111
+ function makeFileWritable ( dest , srcMode ) {
117
112
return setDestMode ( dest , srcMode | 0o200 )
118
113
}
119
114
120
- async function setDestTimestampsAndMode ( srcMode , src , dest ) {
121
- await setDestTimestamps ( src , dest )
122
- return setDestMode ( dest , srcMode )
123
- }
124
-
125
- function setDestMode ( dest , srcMode ) {
126
- return fs . chmod ( dest , srcMode )
127
- }
128
-
129
- async function setDestTimestamps ( src , dest ) {
115
+ async function setDestTimestampsAndMode ( srcMode , src , dest ) {
130
116
// The initial srcStat.atime cannot be trusted
131
117
// because it is modified by the read(2) system call
132
- // (See https://nodejs.org/api/fs.html#fs$stat_time_values )
118
+ // (See https://nodejs.org/api/fs.html#fs_stat_time_values )
133
119
const updatedSrcStat = await fs . stat ( src )
120
+ await utimesMillisAsync ( dest , updatedSrcStat . atime , updatedSrcStat . mtime )
134
121
135
- return utimesMillisAsync ( dest , updatedSrcStat . atime , updatedSrcStat . mtime )
122
+ return setDestMode ( dest , srcMode )
136
123
}
137
124
138
- function onDir ( srcStat , destStat , src , dest , opts ) {
139
- if ( ! destStat ) return mkDirAndCopy ( srcStat . mode , src , dest , opts )
140
- return copyDir ( src , dest , opts )
125
+ function setDestMode ( dest , srcMode ) {
126
+ return fs . chmod ( dest , srcMode )
141
127
}
142
128
143
- async function mkDirAndCopy ( srcMode , src , dest , opts ) {
144
- await fs . mkdir ( dest )
129
+ async function onDir ( srcStat , destStat , src , dest , opts ) {
130
+ if ( ! destStat ) {
131
+ await fs . mkdir ( dest )
132
+ }
145
133
await copyDir ( src , dest , opts )
146
-
147
- return setDestMode ( dest , srcMode )
134
+ if ( ! destStat ) {
135
+ await setDestMode ( dest , srcMode )
136
+ }
148
137
}
149
138
150
- async function copyDir ( src , dest , opts ) {
139
+ async function copyDir ( src , dest , opts ) {
151
140
const items = await fs . readdir ( src )
152
141
return copyDirItems ( items , src , dest , opts )
153
142
}
154
143
155
- function copyDirItems ( items , src , dest , opts ) {
144
+ function copyDirItems ( items , src , dest , opts ) {
156
145
const item = items . pop ( )
157
146
if ( ! item ) return
158
147
return copyDirItem ( items , item , src , dest , opts )
159
148
}
160
149
161
- async function copyDirItem ( items , item , src , dest , opts ) {
150
+ async function copyDirItem ( items , item , src , dest , opts ) {
162
151
const srcItem = path . join ( src , item )
163
152
const destItem = path . join ( dest , item )
164
153
@@ -172,7 +161,7 @@ async function copyDirItem (items, item, src, dest, opts) {
172
161
return copyDirItems ( items , src , dest , opts )
173
162
}
174
163
175
- async function onLink ( destStat , src , dest , opts ) {
164
+ async function onLink ( destStat , src , dest , opts ) {
176
165
let resolvedSrc = await fs . readlink ( src )
177
166
if ( opts . dereference ) {
178
167
resolvedSrc = path . resolve ( process . cwd ( ) , resolvedSrc )
@@ -185,6 +174,9 @@ async function onLink (destStat, src, dest, opts) {
185
174
try {
186
175
resolvedDest = await fs . readlink ( dest )
187
176
} catch ( e ) {
177
+ // dest exists and is a regular file or directory,
178
+ // Windows may throw UNKNOWN error. If dest already exists,
179
+ // fs throws error anyway, so no need to guard against it here.
188
180
if ( e . code === 'EINVAL' || e . code === 'UNKNOWN' ) return fs . symlink ( resolvedSrc , dest )
189
181
throw e
190
182
}
@@ -202,10 +194,6 @@ async function onLink (destStat, src, dest, opts) {
202
194
throw new Error ( `Cannot overwrite '${ resolvedDest } ' with '${ resolvedSrc } '.` )
203
195
}
204
196
205
- return copyLink ( resolvedSrc , dest )
206
- }
207
-
208
- async function copyLink ( resolvedSrc , dest ) {
209
197
await fs . unlink ( dest )
210
198
return fs . symlink ( resolvedSrc , dest )
211
199
}
0 commit comments