Bones/node_modules/fs-extra/lib/move/index.js
SOUTHERNCO\x2mjbyrn 7efe7605b8 Template Upload
2017-05-17 13:45:25 -04:00

163 lines
3.9 KiB
JavaScript

'use strict'
// most of this code was written by Andrew Kelley
// licensed under the BSD license: see
// https://github.com/andrewrk/node-mv/blob/master/package.json
// this needs a cleanup
const u = require('universalify').fromCallback
const fs = require('graceful-fs')
const ncp = require('../copy/ncp')
const path = require('path')
const remove = require('../remove').remove
const mkdirp = require('../mkdirs').mkdirs
function move (source, dest, options, callback) {
if (typeof options === 'function') {
callback = options
options = {}
}
const shouldMkdirp = ('mkdirp' in options) ? options.mkdirp : true
const overwrite = options.overwrite || options.clobber || false
if (shouldMkdirp) {
mkdirs()
} else {
doRename()
}
function mkdirs () {
mkdirp(path.dirname(dest), err => {
if (err) return callback(err)
doRename()
})
}
function doRename () {
if (path.resolve(source) === path.resolve(dest)) {
fs.access(source, callback)
} else if (overwrite) {
fs.rename(source, dest, err => {
if (!err) return callback()
if (err.code === 'ENOTEMPTY' || err.code === 'EEXIST') {
remove(dest, err => {
if (err) return callback(err)
options.overwrite = false // just overwriteed it, no need to do it again
move(source, dest, options, callback)
})
return
}
// weird Windows shit
if (err.code === 'EPERM') {
setTimeout(() => {
remove(dest, err => {
if (err) return callback(err)
options.overwrite = false
move(source, dest, options, callback)
})
}, 200)
return
}
if (err.code !== 'EXDEV') return callback(err)
moveAcrossDevice(source, dest, overwrite, callback)
})
} else {
fs.link(source, dest, err => {
if (err) {
if (err.code === 'EXDEV' || err.code === 'EISDIR' || err.code === 'EPERM' || err.code === 'ENOTSUP') {
moveAcrossDevice(source, dest, overwrite, callback)
return
}
callback(err)
return
}
fs.unlink(source, callback)
})
}
}
}
function moveAcrossDevice (source, dest, overwrite, callback) {
fs.stat(source, (err, stat) => {
if (err) {
callback(err)
return
}
if (stat.isDirectory()) {
moveDirAcrossDevice(source, dest, overwrite, callback)
} else {
moveFileAcrossDevice(source, dest, overwrite, callback)
}
})
}
function moveFileAcrossDevice (source, dest, overwrite, callback) {
const flags = overwrite ? 'w' : 'wx'
const ins = fs.createReadStream(source)
const outs = fs.createWriteStream(dest, { flags })
ins.on('error', err => {
ins.destroy()
outs.destroy()
outs.removeListener('close', onClose)
// may want to create a directory but `out` line above
// creates an empty file for us: See #108
// don't care about error here
fs.unlink(dest, () => {
// note: `err` here is from the input stream errror
if (err.code === 'EISDIR' || err.code === 'EPERM') {
moveDirAcrossDevice(source, dest, overwrite, callback)
} else {
callback(err)
}
})
})
outs.on('error', err => {
ins.destroy()
outs.destroy()
outs.removeListener('close', onClose)
callback(err)
})
outs.once('close', onClose)
ins.pipe(outs)
function onClose () {
fs.unlink(source, callback)
}
}
function moveDirAcrossDevice (source, dest, overwrite, callback) {
const options = {
overwrite: false
}
if (overwrite) {
remove(dest, err => {
if (err) return callback(err)
startNcp()
})
} else {
startNcp()
}
function startNcp () {
ncp(source, dest, options, err => {
if (err) return callback(err)
remove(source, callback)
})
}
}
module.exports = {
move: u(move)
}