You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							161 lines
						
					
					
						
							3.9 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							161 lines
						
					
					
						
							3.9 KiB
						
					
					
				
								// 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
							 | 
						|
								
							 | 
						|
								var fs = require('graceful-fs')
							 | 
						|
								var ncp = require('../copy/ncp')
							 | 
						|
								var path = require('path')
							 | 
						|
								var remove = require('../remove').remove
							 | 
						|
								var mkdirp = require('../mkdirs').mkdirs
							 | 
						|
								
							 | 
						|
								function mv (source, dest, options, callback) {
							 | 
						|
								  if (typeof options === 'function') {
							 | 
						|
								    callback = options
							 | 
						|
								    options = {}
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  var shouldMkdirp = ('mkdirp' in options) ? options.mkdirp : true
							 | 
						|
								  var clobber = ('clobber' in options) ? options.clobber : false
							 | 
						|
								
							 | 
						|
								  var limit = options.limit || 16
							 | 
						|
								
							 | 
						|
								  if (shouldMkdirp) {
							 | 
						|
								    mkdirs()
							 | 
						|
								  } else {
							 | 
						|
								    doRename()
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  function mkdirs () {
							 | 
						|
								    mkdirp(path.dirname(dest), function (err) {
							 | 
						|
								      if (err) return callback(err)
							 | 
						|
								      doRename()
							 | 
						|
								    })
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  function doRename () {
							 | 
						|
								    if (clobber) {
							 | 
						|
								      fs.rename(source, dest, function (err) {
							 | 
						|
								        if (!err) return callback()
							 | 
						|
								
							 | 
						|
								        if (err.code === 'ENOTEMPTY' || err.code === 'EEXIST') {
							 | 
						|
								          remove(dest, function (err) {
							 | 
						|
								            if (err) return callback(err)
							 | 
						|
								            options.clobber = false // just clobbered it, no need to do it again
							 | 
						|
								            mv(source, dest, options, callback)
							 | 
						|
								          })
							 | 
						|
								          return
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // weird Windows shit
							 | 
						|
								        if (err.code === 'EPERM') {
							 | 
						|
								          setTimeout(function () {
							 | 
						|
								            remove(dest, function (err) {
							 | 
						|
								              if (err) return callback(err)
							 | 
						|
								              options.clobber = false
							 | 
						|
								              mv(source, dest, options, callback)
							 | 
						|
								            })
							 | 
						|
								          }, 200)
							 | 
						|
								          return
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        if (err.code !== 'EXDEV') return callback(err)
							 | 
						|
								        moveAcrossDevice(source, dest, clobber, limit, callback)
							 | 
						|
								      })
							 | 
						|
								    } else {
							 | 
						|
								      fs.link(source, dest, function (err) {
							 | 
						|
								        if (err) {
							 | 
						|
								          if (err.code === 'EXDEV' || err.code === 'EISDIR' || err.code === 'EPERM') {
							 | 
						|
								            moveAcrossDevice(source, dest, clobber, limit, callback)
							 | 
						|
								            return
							 | 
						|
								          }
							 | 
						|
								          callback(err)
							 | 
						|
								          return
							 | 
						|
								        }
							 | 
						|
								        fs.unlink(source, callback)
							 | 
						|
								      })
							 | 
						|
								    }
							 | 
						|
								  }
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								function moveAcrossDevice (source, dest, clobber, limit, callback) {
							 | 
						|
								  fs.stat(source, function (err, stat) {
							 | 
						|
								    if (err) {
							 | 
						|
								      callback(err)
							 | 
						|
								      return
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    if (stat.isDirectory()) {
							 | 
						|
								      moveDirAcrossDevice(source, dest, clobber, limit, callback)
							 | 
						|
								    } else {
							 | 
						|
								      moveFileAcrossDevice(source, dest, clobber, limit, callback)
							 | 
						|
								    }
							 | 
						|
								  })
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								function moveFileAcrossDevice (source, dest, clobber, limit, callback) {
							 | 
						|
								  var outFlags = clobber ? 'w' : 'wx'
							 | 
						|
								  var ins = fs.createReadStream(source)
							 | 
						|
								  var outs = fs.createWriteStream(dest, {flags: outFlags})
							 | 
						|
								
							 | 
						|
								  ins.on('error', function (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, function () {
							 | 
						|
								      // note: `err` here is from the input stream errror
							 | 
						|
								      if (err.code === 'EISDIR' || err.code === 'EPERM') {
							 | 
						|
								        moveDirAcrossDevice(source, dest, clobber, limit, callback)
							 | 
						|
								      } else {
							 | 
						|
								        callback(err)
							 | 
						|
								      }
							 | 
						|
								    })
							 | 
						|
								  })
							 | 
						|
								
							 | 
						|
								  outs.on('error', function (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, clobber, limit, callback) {
							 | 
						|
								  var options = {
							 | 
						|
								    stopOnErr: true,
							 | 
						|
								    clobber: false,
							 | 
						|
								    limit: limit
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  function startNcp () {
							 | 
						|
								    ncp(source, dest, options, function (errList) {
							 | 
						|
								      if (errList) return callback(errList[0])
							 | 
						|
								      remove(source, callback)
							 | 
						|
								    })
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  if (clobber) {
							 | 
						|
								    remove(dest, function (err) {
							 | 
						|
								      if (err) return callback(err)
							 | 
						|
								      startNcp()
							 | 
						|
								    })
							 | 
						|
								  } else {
							 | 
						|
								    startNcp()
							 | 
						|
								  }
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								module.exports = {
							 | 
						|
								  move: mv
							 | 
						|
								}
							 | 
						|
								
							 |