Skip to content

Commit 40c5161

Browse files
authoredOct 24, 2023
Refactor copy API to async/await (#1021)
1 parent 6f2b2bc commit 40c5161

11 files changed

+202
-249
lines changed
 

‎lib/copy/__tests__/copy-broken-symlink.test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const os = require('os')
55
const fse = require('../..')
66
const path = require('path')
77
const assert = require('assert')
8-
const copy = require('../copy')
8+
const { copy } = require('../')
99

1010
/* global afterEach, beforeEach, describe, it */
1111

‎lib/copy/__tests__/copy-preserve-timestamp.test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
const fs = require('../../')
44
const os = require('os')
55
const path = require('path')
6-
const copy = require('../copy')
6+
const { copy } = require('../')
77
const utimesSync = require('../../util/utimes').utimesMillisSync
88
const assert = require('assert')
99

‎lib/copy/__tests__/ncp/broken-symlink.test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
const fs = require('fs')
44
const os = require('os')
55
const fse = require('../../..')
6-
const ncp = require('../../copy')
6+
const { copy: ncp } = require('../../')
77
const path = require('path')
88
const assert = require('assert')
99

‎lib/copy/__tests__/ncp/ncp-error-perm.test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
const fs = require('fs')
66
const os = require('os')
77
const fse = require('../../..')
8-
const ncp = require('../../copy')
8+
const { copy: ncp } = require('../../')
99
const path = require('path')
1010
const assert = require('assert')
1111

‎lib/copy/__tests__/ncp/ncp.test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use strict'
22

33
const fs = require('fs')
4-
const ncp = require('../../copy')
4+
const { copy: ncp } = require('../../')
55
const path = require('path')
66
const rimraf = require('rimraf')
77
const assert = require('assert')

‎lib/copy/__tests__/ncp/symlink.test.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
const fs = require('fs')
44
const os = require('os')
55
const fse = require('../../..')
6-
const ncp = require('../../copy')
6+
const { copy: ncp } = require('../../')
77
const path = require('path')
88
const assert = require('assert')
99

‎lib/copy/copy.js

+120-183
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,17 @@
11
'use strict'
22

3-
const fs = require('graceful-fs')
3+
const fs = require('../fs')
44
const path = require('path')
5-
const mkdirs = require('../mkdirs').mkdirs
6-
const pathExists = require('../path-exists').pathExists
7-
const utimesMillis = require('../util/utimes').utimesMillis
5+
const { mkdirs } = require('../mkdirs')
6+
const { pathExists } = require('../path-exists')
7+
const { utimesMillis } = require('../util/utimes')
88
const stat = require('../util/stat')
99

10-
function copy (src, dest, opts, cb) {
11-
if (typeof opts === 'function' && !cb) {
12-
cb = opts
13-
opts = {}
14-
} else if (typeof opts === 'function') {
10+
async function copy (src, dest, opts = {}) {
11+
if (typeof opts === 'function') {
1512
opts = { filter: opts }
1613
}
1714

18-
cb = cb || function () {}
19-
opts = opts || {}
20-
2115
opts.clobber = 'clobber' in opts ? !!opts.clobber : true // default to true for now
2216
opts.overwrite = 'overwrite' in opts ? !!opts.overwrite : opts.clobber // overwrite falls back to clobber
2317

@@ -30,209 +24,152 @@ function copy (src, dest, opts, cb) {
3024
)
3125
}
3226

33-
stat.checkPaths(src, dest, 'copy', opts, (err, stats) => {
34-
if (err) return cb(err)
35-
const { srcStat, destStat } = stats
36-
stat.checkParentPaths(src, srcStat, dest, 'copy', err => {
37-
if (err) return cb(err)
38-
runFilter(src, dest, opts, (err, include) => {
39-
if (err) return cb(err)
40-
if (!include) return cb()
41-
42-
checkParentDir(destStat, src, dest, opts, cb)
43-
})
44-
})
45-
})
46-
}
27+
const { srcStat, destStat } = await stat.checkPaths(src, dest, 'copy', opts)
28+
29+
await stat.checkParentPaths(src, srcStat, dest, 'copy')
30+
31+
const include = await runFilter(src, dest, opts)
32+
33+
if (!include) return
4734

48-
function checkParentDir (destStat, src, dest, opts, cb) {
35+
// check if the parent of dest exists, and create it if it doesn't exist
4936
const destParent = path.dirname(dest)
50-
pathExists(destParent, (err, dirExists) => {
51-
if (err) return cb(err)
52-
if (dirExists) return getStats(destStat, src, dest, opts, cb)
53-
mkdirs(destParent, err => {
54-
if (err) return cb(err)
55-
return getStats(destStat, src, dest, opts, cb)
56-
})
57-
})
58-
}
37+
const dirExists = await pathExists(destParent)
38+
if (!dirExists) {
39+
await mkdirs(destParent)
40+
}
5941

60-
function runFilter (src, dest, opts, cb) {
61-
if (!opts.filter) return cb(null, true)
62-
Promise.resolve(opts.filter(src, dest))
63-
.then(include => cb(null, include), error => cb(error))
42+
await getStatsAndPerformCopy(destStat, src, dest, opts)
6443
}
6544

66-
function getStats (destStat, src, dest, opts, cb) {
67-
const stat = opts.dereference ? fs.stat : fs.lstat
68-
stat(src, (err, srcStat) => {
69-
if (err) return cb(err)
70-
71-
if (srcStat.isDirectory()) return onDir(srcStat, destStat, src, dest, opts, cb)
72-
else if (srcStat.isFile() ||
73-
srcStat.isCharacterDevice() ||
74-
srcStat.isBlockDevice()) return onFile(srcStat, destStat, src, dest, opts, cb)
75-
else if (srcStat.isSymbolicLink()) return onLink(destStat, src, dest, opts, cb)
76-
else if (srcStat.isSocket()) return cb(new Error(`Cannot copy a socket file: ${src}`))
77-
else if (srcStat.isFIFO()) return cb(new Error(`Cannot copy a FIFO pipe: ${src}`))
78-
return cb(new Error(`Unknown file: ${src}`))
79-
})
45+
async function runFilter (src, dest, opts) {
46+
if (!opts.filter) return true
47+
return opts.filter(src, dest)
8048
}
8149

82-
function onFile (srcStat, destStat, src, dest, opts, cb) {
83-
if (!destStat) return copyFile(srcStat, src, dest, opts, cb)
84-
return mayCopyFile(srcStat, src, dest, opts, cb)
50+
async function getStatsAndPerformCopy (destStat, src, dest, opts) {
51+
const statFn = opts.dereference ? fs.stat : fs.lstat
52+
const srcStat = await statFn(src)
53+
54+
if (srcStat.isDirectory()) return onDir(srcStat, destStat, src, dest, opts)
55+
56+
if (
57+
srcStat.isFile() ||
58+
srcStat.isCharacterDevice() ||
59+
srcStat.isBlockDevice()
60+
) return onFile(srcStat, destStat, src, dest, opts)
61+
62+
if (srcStat.isSymbolicLink()) return onLink(destStat, src, dest, opts)
63+
if (srcStat.isSocket()) throw new Error(`Cannot copy a socket file: ${src}`)
64+
if (srcStat.isFIFO()) throw new Error(`Cannot copy a FIFO pipe: ${src}`)
65+
throw new Error(`Unknown file: ${src}`)
8566
}
8667

87-
function mayCopyFile (srcStat, src, dest, opts, cb) {
68+
async function onFile (srcStat, destStat, src, dest, opts) {
69+
if (!destStat) return copyFile(srcStat, src, dest, opts)
70+
8871
if (opts.overwrite) {
89-
fs.unlink(dest, err => {
90-
if (err) return cb(err)
91-
return copyFile(srcStat, src, dest, opts, cb)
92-
})
93-
} else if (opts.errorOnExist) {
94-
return cb(new Error(`'${dest}' already exists`))
95-
} else return cb()
72+
await fs.unlink(dest)
73+
return copyFile(srcStat, src, dest, opts)
74+
}
75+
if (opts.errorOnExist) {
76+
throw new Error(`'${dest}' already exists`)
77+
}
9678
}
9779

98-
function copyFile (srcStat, src, dest, opts, cb) {
99-
fs.copyFile(src, dest, err => {
100-
if (err) return cb(err)
101-
if (opts.preserveTimestamps) return handleTimestampsAndMode(srcStat.mode, src, dest, cb)
102-
return setDestMode(dest, srcStat.mode, cb)
103-
})
104-
}
80+
async function copyFile (srcStat, src, dest, opts) {
81+
await fs.copyFile(src, dest)
82+
if (opts.preserveTimestamps) {
83+
// Make sure the file is writable before setting the timestamp
84+
// otherwise open fails with EPERM when invoked with 'r+'
85+
// (through utimes call)
86+
if (fileIsNotWritable(srcStat.mode)) {
87+
await makeFileWritable(dest, srcStat.mode)
88+
}
10589

106-
function handleTimestampsAndMode (srcMode, src, dest, cb) {
107-
// Make sure the file is writable before setting the timestamp
108-
// otherwise open fails with EPERM when invoked with 'r+'
109-
// (through utimes call)
110-
if (fileIsNotWritable(srcMode)) {
111-
return makeFileWritable(dest, srcMode, err => {
112-
if (err) return cb(err)
113-
return setDestTimestampsAndMode(srcMode, src, dest, cb)
114-
})
90+
// Set timestamps and mode correspondingly
91+
92+
// Note that The initial srcStat.atime cannot be trusted
93+
// because it is modified by the read(2) system call
94+
// (See https://nodejs.org/api/fs.html#fs_stat_time_values)
95+
const updatedSrcStat = await fs.stat(src)
96+
await utimesMillis(dest, updatedSrcStat.atime, updatedSrcStat.mtime)
11597
}
116-
return setDestTimestampsAndMode(srcMode, src, dest, cb)
98+
99+
return fs.chmod(dest, srcStat.mode)
117100
}
118101

119102
function fileIsNotWritable (srcMode) {
120103
return (srcMode & 0o200) === 0
121104
}
122105

123-
function makeFileWritable (dest, srcMode, cb) {
124-
return setDestMode(dest, srcMode | 0o200, cb)
125-
}
126-
127-
function setDestTimestampsAndMode (srcMode, src, dest, cb) {
128-
setDestTimestamps(src, dest, err => {
129-
if (err) return cb(err)
130-
return setDestMode(dest, srcMode, cb)
131-
})
106+
function makeFileWritable (dest, srcMode) {
107+
return fs.chmod(dest, srcMode | 0o200)
132108
}
133109

134-
function setDestMode (dest, srcMode, cb) {
135-
return fs.chmod(dest, srcMode, cb)
136-
}
110+
async function onDir (srcStat, destStat, src, dest, opts) {
111+
// the dest directory might not exist, create it
112+
if (!destStat) {
113+
await fs.mkdir(dest)
114+
}
137115

138-
function setDestTimestamps (src, dest, cb) {
139-
// The initial srcStat.atime cannot be trusted
140-
// because it is modified by the read(2) system call
141-
// (See https://nodejs.org/api/fs.html#fs_stat_time_values)
142-
fs.stat(src, (err, updatedSrcStat) => {
143-
if (err) return cb(err)
144-
return utimesMillis(dest, updatedSrcStat.atime, updatedSrcStat.mtime, cb)
145-
})
146-
}
116+
// loop through the files in the current directory to copy everything
117+
for (const item of await fs.readdir(src)) {
118+
const srcItem = path.join(src, item)
119+
const destItem = path.join(dest, item)
147120

148-
function onDir (srcStat, destStat, src, dest, opts, cb) {
149-
if (!destStat) return mkDirAndCopy(srcStat.mode, src, dest, opts, cb)
150-
return copyDir(src, dest, opts, cb)
151-
}
121+
// skip the item if it is matches by the filter function
122+
const include = await runFilter(srcItem, destItem, opts)
123+
if (!include) continue
152124

153-
function mkDirAndCopy (srcMode, src, dest, opts, cb) {
154-
fs.mkdir(dest, err => {
155-
if (err) return cb(err)
156-
copyDir(src, dest, opts, err => {
157-
if (err) return cb(err)
158-
return setDestMode(dest, srcMode, cb)
159-
})
160-
})
161-
}
125+
const { destStat } = await stat.checkPaths(srcItem, destItem, 'copy', opts)
162126

163-
function copyDir (src, dest, opts, cb) {
164-
fs.readdir(src, (err, items) => {
165-
if (err) return cb(err)
166-
return copyDirItems(items, src, dest, opts, cb)
167-
})
168-
}
127+
// If the item is a copyable file, `getStatsAndPerformCopy` will copy it
128+
// If the item is a directory, `getStatsAndPerformCopy` will call `onDir` recursively
129+
await getStatsAndPerformCopy(destStat, srcItem, destItem, opts)
130+
}
169131

170-
function copyDirItems (items, src, dest, opts, cb) {
171-
const item = items.pop()
172-
if (!item) return cb()
173-
return copyDirItem(items, item, src, dest, opts, cb)
132+
if (!destStat) {
133+
await fs.chmod(dest, srcStat.mode)
134+
}
174135
}
175136

176-
function copyDirItem (items, item, src, dest, opts, cb) {
177-
const srcItem = path.join(src, item)
178-
const destItem = path.join(dest, item)
179-
runFilter(srcItem, destItem, opts, (err, include) => {
180-
if (err) return cb(err)
181-
if (!include) return copyDirItems(items, src, dest, opts, cb)
182-
183-
stat.checkPaths(srcItem, destItem, 'copy', opts, (err, stats) => {
184-
if (err) return cb(err)
185-
const { destStat } = stats
186-
getStats(destStat, srcItem, destItem, opts, err => {
187-
if (err) return cb(err)
188-
return copyDirItems(items, src, dest, opts, cb)
189-
})
190-
})
191-
})
192-
}
137+
async function onLink (destStat, src, dest, opts) {
138+
let resolvedSrc = await fs.readlink(src)
139+
if (opts.dereference) {
140+
resolvedSrc = path.resolve(process.cwd(), resolvedSrc)
141+
}
142+
if (!destStat) {
143+
return fs.symlink(resolvedSrc, dest)
144+
}
193145

194-
function onLink (destStat, src, dest, opts, cb) {
195-
fs.readlink(src, (err, resolvedSrc) => {
196-
if (err) return cb(err)
197-
if (opts.dereference) {
198-
resolvedSrc = path.resolve(process.cwd(), resolvedSrc)
199-
}
146+
let resolvedDest = null
147+
try {
148+
resolvedDest = await fs.readlink(dest)
149+
} catch (e) {
150+
// dest exists and is a regular file or directory,
151+
// Windows may throw UNKNOWN error. If dest already exists,
152+
// fs throws error anyway, so no need to guard against it here.
153+
if (e.code === 'EINVAL' || e.code === 'UNKNOWN') return fs.symlink(resolvedSrc, dest)
154+
throw e
155+
}
156+
if (opts.dereference) {
157+
resolvedDest = path.resolve(process.cwd(), resolvedDest)
158+
}
159+
if (stat.isSrcSubdir(resolvedSrc, resolvedDest)) {
160+
throw new Error(`Cannot copy '${resolvedSrc}' to a subdirectory of itself, '${resolvedDest}'.`)
161+
}
200162

201-
if (!destStat) {
202-
return fs.symlink(resolvedSrc, dest, cb)
203-
} else {
204-
fs.readlink(dest, (err, resolvedDest) => {
205-
if (err) {
206-
// dest exists and is a regular file or directory,
207-
// Windows may throw UNKNOWN error. If dest already exists,
208-
// fs throws error anyway, so no need to guard against it here.
209-
if (err.code === 'EINVAL' || err.code === 'UNKNOWN') return fs.symlink(resolvedSrc, dest, cb)
210-
return cb(err)
211-
}
212-
if (opts.dereference) {
213-
resolvedDest = path.resolve(process.cwd(), resolvedDest)
214-
}
215-
if (stat.isSrcSubdir(resolvedSrc, resolvedDest)) {
216-
return cb(new Error(`Cannot copy '${resolvedSrc}' to a subdirectory of itself, '${resolvedDest}'.`))
217-
}
218-
219-
// do not copy if src is a subdir of dest since unlinking
220-
// dest in this case would result in removing src contents
221-
// and therefore a broken symlink would be created.
222-
if (stat.isSrcSubdir(resolvedDest, resolvedSrc)) {
223-
return cb(new Error(`Cannot overwrite '${resolvedDest}' with '${resolvedSrc}'.`))
224-
}
225-
return copyLink(resolvedSrc, dest, cb)
226-
})
227-
}
228-
})
229-
}
163+
// do not copy if src is a subdir of dest since unlinking
164+
// dest in this case would result in removing src contents
165+
// and therefore a broken symlink would be created.
166+
if (stat.isSrcSubdir(resolvedDest, resolvedSrc)) {
167+
throw new Error(`Cannot overwrite '${resolvedDest}' with '${resolvedSrc}'.`)
168+
}
230169

231-
function copyLink (resolvedSrc, dest, cb) {
232-
fs.unlink(dest, err => {
233-
if (err) return cb(err)
234-
return fs.symlink(resolvedSrc, dest, cb)
235-
})
170+
// copy the link
171+
await fs.unlink(dest)
172+
return fs.symlink(resolvedSrc, dest)
236173
}
237174

238175
module.exports = copy

‎lib/copy/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict'
22

3-
const u = require('universalify').fromCallback
3+
const u = require('universalify').fromPromise
44
module.exports = {
55
copy: u(require('./copy')),
66
copySync: require('./copy-sync')

‎lib/util/__tests__/utimes.test.js

+9-7
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ const fse = require('../..')
66
const path = require('path')
77
const assert = require('assert')
88
const proxyquire = require('proxyquire')
9+
const u = require('universalify').fromCallback
10+
911
let gracefulFsStub
1012
let utimes
1113

@@ -33,7 +35,7 @@ describe('utimes', () => {
3335
fse.emptyDir(TEST_DIR, done)
3436
// reset stubs
3537
gracefulFsStub = {}
36-
utimes = proxyquire('../utimes', { 'graceful-fs': gracefulFsStub })
38+
utimes = proxyquire('../utimes', { '../fs': gracefulFsStub })
3739
})
3840

3941
describe('utimesMillis()', () => {
@@ -68,25 +70,25 @@ describe('utimes', () => {
6870
it('should close open file desciptors after encountering an error', done => {
6971
const fakeFd = Math.random()
7072

71-
gracefulFsStub.open = (pathIgnored, flagsIgnored, modeIgnored, callback) => {
73+
gracefulFsStub.open = u((pathIgnored, flagsIgnored, modeIgnored, callback) => {
7274
if (typeof modeIgnored === 'function') callback = modeIgnored
7375
process.nextTick(() => callback(null, fakeFd))
74-
}
76+
})
7577

7678
let closeCalled = false
77-
gracefulFsStub.close = (fd, callback) => {
79+
gracefulFsStub.close = u((fd, callback) => {
7880
assert.strictEqual(fd, fakeFd)
7981
closeCalled = true
8082
if (callback) process.nextTick(callback)
81-
}
83+
})
8284

8385
let testError
84-
gracefulFsStub.futimes = (fd, atimeIgnored, mtimeIgnored, callback) => {
86+
gracefulFsStub.futimes = u((fd, atimeIgnored, mtimeIgnored, callback) => {
8587
process.nextTick(() => {
8688
testError = new Error('A test error')
8789
callback(testError)
8890
})
89-
}
91+
})
9092

9193
utimes.utimesMillis('ignored', 'ignored', 'ignored', err => {
9294
assert.strictEqual(err, testError)

‎lib/util/stat.js

+45-41
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
const fs = require('../fs')
44
const path = require('path')
5-
const util = require('util')
5+
const u = require('universalify').fromPromise
66

77
function getStats (src, dest, opts) {
88
const statFunc = opts.dereference
@@ -32,35 +32,32 @@ function getStatsSync (src, dest, opts) {
3232
return { srcStat, destStat }
3333
}
3434

35-
function checkPaths (src, dest, funcName, opts, cb) {
36-
util.callbackify(getStats)(src, dest, opts, (err, stats) => {
37-
if (err) return cb(err)
38-
const { srcStat, destStat } = stats
39-
40-
if (destStat) {
41-
if (areIdentical(srcStat, destStat)) {
42-
const srcBaseName = path.basename(src)
43-
const destBaseName = path.basename(dest)
44-
if (funcName === 'move' &&
45-
srcBaseName !== destBaseName &&
46-
srcBaseName.toLowerCase() === destBaseName.toLowerCase()) {
47-
return cb(null, { srcStat, destStat, isChangingCase: true })
48-
}
49-
return cb(new Error('Source and destination must not be the same.'))
50-
}
51-
if (srcStat.isDirectory() && !destStat.isDirectory()) {
52-
return cb(new Error(`Cannot overwrite non-directory '${dest}' with directory '${src}'.`))
53-
}
54-
if (!srcStat.isDirectory() && destStat.isDirectory()) {
55-
return cb(new Error(`Cannot overwrite directory '${dest}' with non-directory '${src}'.`))
35+
async function checkPaths (src, dest, funcName, opts) {
36+
const { srcStat, destStat } = await getStats(src, dest, opts)
37+
if (destStat) {
38+
if (areIdentical(srcStat, destStat)) {
39+
const srcBaseName = path.basename(src)
40+
const destBaseName = path.basename(dest)
41+
if (funcName === 'move' &&
42+
srcBaseName !== destBaseName &&
43+
srcBaseName.toLowerCase() === destBaseName.toLowerCase()) {
44+
return { srcStat, destStat, isChangingCase: true }
5645
}
46+
throw new Error('Source and destination must not be the same.')
5747
}
58-
59-
if (srcStat.isDirectory() && isSrcSubdir(src, dest)) {
60-
return cb(new Error(errMsg(src, dest, funcName)))
48+
if (srcStat.isDirectory() && !destStat.isDirectory()) {
49+
throw new Error(`Cannot overwrite non-directory '${dest}' with directory '${src}'.`)
50+
}
51+
if (!srcStat.isDirectory() && destStat.isDirectory()) {
52+
throw new Error(`Cannot overwrite directory '${dest}' with non-directory '${src}'.`)
6153
}
62-
return cb(null, { srcStat, destStat })
63-
})
54+
}
55+
56+
if (srcStat.isDirectory() && isSrcSubdir(src, dest)) {
57+
throw new Error(errMsg(src, dest, funcName))
58+
}
59+
60+
return { srcStat, destStat }
6461
}
6562

6663
function checkPathsSync (src, dest, funcName, opts) {
@@ -95,20 +92,24 @@ function checkPathsSync (src, dest, funcName, opts) {
9592
// It works for all file types including symlinks since it
9693
// checks the src and dest inodes. It starts from the deepest
9794
// parent and stops once it reaches the src parent or the root path.
98-
function checkParentPaths (src, srcStat, dest, funcName, cb) {
95+
async function checkParentPaths (src, srcStat, dest, funcName) {
9996
const srcParent = path.resolve(path.dirname(src))
10097
const destParent = path.resolve(path.dirname(dest))
101-
if (destParent === srcParent || destParent === path.parse(destParent).root) return cb()
102-
fs.stat(destParent, { bigint: true }, (err, destStat) => {
103-
if (err) {
104-
if (err.code === 'ENOENT') return cb()
105-
return cb(err)
106-
}
107-
if (areIdentical(srcStat, destStat)) {
108-
return cb(new Error(errMsg(src, dest, funcName)))
109-
}
110-
return checkParentPaths(src, srcStat, destParent, funcName, cb)
111-
})
98+
if (destParent === srcParent || destParent === path.parse(destParent).root) return
99+
100+
let destStat
101+
try {
102+
destStat = await fs.stat(destParent, { bigint: true })
103+
} catch (err) {
104+
if (err.code === 'ENOENT') return
105+
throw err
106+
}
107+
108+
if (areIdentical(srcStat, destStat)) {
109+
throw new Error(errMsg(src, dest, funcName))
110+
}
111+
112+
return checkParentPaths(src, srcStat, destParent, funcName)
112113
}
113114

114115
function checkParentPathsSync (src, srcStat, dest, funcName) {
@@ -145,10 +146,13 @@ function errMsg (src, dest, funcName) {
145146
}
146147

147148
module.exports = {
148-
checkPaths,
149+
// checkPaths
150+
checkPaths: u(checkPaths),
149151
checkPathsSync,
150-
checkParentPaths,
152+
// checkParent
153+
checkParentPaths: u(checkParentPaths),
151154
checkParentPathsSync,
155+
// Misc
152156
isSrcSubdir,
153157
areIdentical
154158
}

‎lib/util/utimes.js

+21-11
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,27 @@
11
'use strict'
22

3-
const fs = require('graceful-fs')
3+
const fs = require('../fs')
4+
const u = require('universalify').fromPromise
45

5-
function utimesMillis (path, atime, mtime, callback) {
6+
async function utimesMillis (path, atime, mtime) {
67
// if (!HAS_MILLIS_RES) return fs.utimes(path, atime, mtime, callback)
7-
fs.open(path, 'r+', (err, fd) => {
8-
if (err) return callback(err)
9-
fs.futimes(fd, atime, mtime, futimesErr => {
10-
fs.close(fd, closeErr => {
11-
if (callback) callback(futimesErr || closeErr)
12-
})
13-
})
14-
})
8+
const fd = await fs.open(path, 'r+')
9+
10+
let closeErr = null
11+
12+
try {
13+
await fs.futimes(fd, atime, mtime)
14+
} finally {
15+
try {
16+
await fs.close(fd)
17+
} catch (e) {
18+
closeErr = e
19+
}
20+
}
21+
22+
if (closeErr) {
23+
throw closeErr
24+
}
1525
}
1626

1727
function utimesMillisSync (path, atime, mtime) {
@@ -21,6 +31,6 @@ function utimesMillisSync (path, atime, mtime) {
2131
}
2232

2333
module.exports = {
24-
utimesMillis,
34+
utimesMillis: u(utimesMillis),
2535
utimesMillisSync
2636
}

0 commit comments

Comments
 (0)
Please sign in to comment.