83 lines
		
	
	
		
			1.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			83 lines
		
	
	
		
			1.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|  | 'use strict' | ||
|  | 
 | ||
|  | const u = require('universalify').fromCallback | ||
|  | const fs = require('graceful-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 | ||
|  | 
 | ||
|  | function move (src, dest, opts, cb) { | ||
|  |   if (typeof opts === 'function') { | ||
|  |     cb = opts | ||
|  |     opts = {} | ||
|  |   } | ||
|  | 
 | ||
|  |   const overwrite = opts.overwrite || opts.clobber || false | ||
|  | 
 | ||
|  |   src = path.resolve(src) | ||
|  |   dest = path.resolve(dest) | ||
|  | 
 | ||
|  |   if (src === dest) return fs.access(src, cb) | ||
|  | 
 | ||
|  |   fs.stat(src, (err, st) => { | ||
|  |     if (err) return cb(err) | ||
|  | 
 | ||
|  |     if (st.isDirectory() && isSrcSubdir(src, dest)) { | ||
|  |       return cb(new Error(`Cannot move '${src}' to a subdirectory of itself, '${dest}'.`)) | ||
|  |     } | ||
|  |     mkdirp(path.dirname(dest), err => { | ||
|  |       if (err) return cb(err) | ||
|  |       return doRename(src, dest, overwrite, cb) | ||
|  |     }) | ||
|  |   }) | ||
|  | } | ||
|  | 
 | ||
|  | function doRename (src, dest, overwrite, cb) { | ||
|  |   if (overwrite) { | ||
|  |     return remove(dest, err => { | ||
|  |       if (err) return cb(err) | ||
|  |       return rename(src, dest, overwrite, cb) | ||
|  |     }) | ||
|  |   } | ||
|  |   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) | ||
|  |   }) | ||
|  | } | ||
|  | 
 | ||
|  | function moveAcrossDevice (src, dest, overwrite, cb) { | ||
|  |   const opts = { | ||
|  |     overwrite, | ||
|  |     errorOnExist: true | ||
|  |   } | ||
|  | 
 | ||
|  |   copy(src, dest, opts, err => { | ||
|  |     if (err) return cb(err) | ||
|  |     return remove(src, cb) | ||
|  |   }) | ||
|  | } | ||
|  | 
 | ||
|  | function isSrcSubdir (src, dest) { | ||
|  |   const srcArray = src.split(path.sep) | ||
|  |   const destArray = dest.split(path.sep) | ||
|  | 
 | ||
|  |   return srcArray.reduce((acc, current, i) => { | ||
|  |     return acc && destArray[i] === current | ||
|  |   }, true) | ||
|  | } | ||
|  | 
 | ||
|  | module.exports = { | ||
|  |   move: u(move) | ||
|  | } |