Skip to content

Commit

Permalink
Refactor move API to async/await (#1025)
Browse files Browse the repository at this point in the history
  • Loading branch information
SukkaW committed Oct 26, 2023
1 parent 40c5161 commit a277cbb
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 62 deletions.
14 changes: 6 additions & 8 deletions lib/move/__tests__/move.test.js
@@ -1,6 +1,6 @@
'use strict'

const fs = require('graceful-fs')
const fs = require('../../fs')
const os = require('os')
const fse = require('../../')
const path = require('path')
Expand All @@ -12,14 +12,12 @@ const { differentDevice, ifCrossDeviceEnabled } = require('./cross-device-utils'
const describeIfWindows = process.platform === 'win32' ? describe : describe.skip

function createAsyncErrFn (errCode) {
const fn = function (...args) {
async function fn () {
fn.callCount++
const callback = args.pop()
setTimeout(() => {
const err = new Error()
err.code = errCode
callback(err)
}, 10)
const err = new Error()
err.code = errCode

return Promise.reject(err)
}
fn.callCount = 0
return fn
Expand Down
2 changes: 1 addition & 1 deletion lib/move/index.js
@@ -1,6 +1,6 @@
'use strict'

const u = require('universalify').fromCallback
const u = require('universalify').fromPromise
module.exports = {
move: u(require('./move')),
moveSync: require('./move-sync')
Expand Down
89 changes: 36 additions & 53 deletions lib/move/move.js
@@ -1,76 +1,59 @@
'use strict'

const fs = require('graceful-fs')
const fs = require('../fs')
const path = require('path')
const copy = require('../copy').copy
const remove = require('../remove').remove
const mkdirp = require('../mkdirs').mkdirp
const pathExists = require('../path-exists').pathExists
const { copy } = require('../copy')
const { remove } = require('../remove')
const { mkdirp } = require('../mkdirs')
const { pathExists } = require('../path-exists')
const stat = require('../util/stat')

function move (src, dest, opts, cb) {
if (typeof opts === 'function') {
cb = opts
opts = {}
}
async function move (src, dest, opts = {}) {
const overwrite = opts.overwrite || opts.clobber || false

opts = opts || {}
const { srcStat, isChangingCase = false } = await stat.checkPaths(src, dest, 'move', opts)

const overwrite = opts.overwrite || opts.clobber || false
await stat.checkParentPaths(src, srcStat, dest, 'move')

stat.checkPaths(src, dest, 'move', opts, (err, stats) => {
if (err) return cb(err)
const { srcStat, isChangingCase = false } = stats
stat.checkParentPaths(src, srcStat, dest, 'move', err => {
if (err) return cb(err)
if (isParentRoot(dest)) return doRename(src, dest, overwrite, isChangingCase, cb)
mkdirp(path.dirname(dest), err => {
if (err) return cb(err)
return doRename(src, dest, overwrite, isChangingCase, cb)
})
})
})
}
// If the parent of dest is not root, make sure it exists before proceeding
const destParent = path.dirname(dest)
const parsedParentPath = path.parse(destParent)
if (parsedParentPath.root !== destParent) {
await mkdirp(destParent)
}

function isParentRoot (dest) {
const parent = path.dirname(dest)
const parsedPath = path.parse(parent)
return parsedPath.root === parent
return doRename(src, dest, overwrite, isChangingCase)
}

function doRename (src, dest, overwrite, isChangingCase, cb) {
if (isChangingCase) return rename(src, dest, overwrite, cb)
if (overwrite) {
return remove(dest, err => {
if (err) return cb(err)
return rename(src, dest, overwrite, cb)
})
async function doRename (src, dest, overwrite, isChangingCase) {
if (!isChangingCase) {
if (overwrite) {
await remove(dest)
} else if (await pathExists(dest)) {
throw new Error('dest already exists.')
}
}
pathExists(dest, (err, destExists) => {
if (err) return cb(err)
if (destExists) return cb(new Error('dest already exists.'))
return rename(src, dest, overwrite, cb)
})
}

function rename (src, dest, overwrite, cb) {
fs.rename(src, dest, err => {
if (!err) return cb()
if (err.code !== 'EXDEV') return cb(err)
return moveAcrossDevice(src, dest, overwrite, cb)
})
try {
// Try w/ rename first, and try copy + remove if EXDEV
await fs.rename(src, dest)
} catch (err) {
if (err.code !== 'EXDEV') {
throw err
}
await moveAcrossDevice(src, dest, overwrite)
}
}

function moveAcrossDevice (src, dest, overwrite, cb) {
async function moveAcrossDevice (src, dest, overwrite) {
const opts = {
overwrite,
errorOnExist: true,
preserveTimestamps: true
}
copy(src, dest, opts, err => {
if (err) return cb(err)
return remove(src, cb)
})

await copy(src, dest, opts)
return remove(src)
}

module.exports = move

0 comments on commit a277cbb

Please sign in to comment.