move.js 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. 'use strict'
  2. const fs = require('graceful-fs')
  3. const path = require('path')
  4. const copy = require('../copy').copy
  5. const remove = require('../remove').remove
  6. const mkdirp = require('../mkdirs').mkdirp
  7. const pathExists = require('../path-exists').pathExists
  8. const stat = require('../util/stat')
  9. function move (src, dest, opts, cb) {
  10. if (typeof opts === 'function') {
  11. cb = opts
  12. opts = {}
  13. }
  14. const overwrite = opts.overwrite || opts.clobber || false
  15. stat.checkPaths(src, dest, 'move', opts, (err, stats) => {
  16. if (err) return cb(err)
  17. const { srcStat, isChangingCase = false } = stats
  18. stat.checkParentPaths(src, srcStat, dest, 'move', err => {
  19. if (err) return cb(err)
  20. if (isParentRoot(dest)) return doRename(src, dest, overwrite, isChangingCase, cb)
  21. mkdirp(path.dirname(dest), err => {
  22. if (err) return cb(err)
  23. return doRename(src, dest, overwrite, isChangingCase, cb)
  24. })
  25. })
  26. })
  27. }
  28. function isParentRoot (dest) {
  29. const parent = path.dirname(dest)
  30. const parsedPath = path.parse(parent)
  31. return parsedPath.root === parent
  32. }
  33. function doRename (src, dest, overwrite, isChangingCase, cb) {
  34. if (isChangingCase) return rename(src, dest, overwrite, cb)
  35. if (overwrite) {
  36. return remove(dest, err => {
  37. if (err) return cb(err)
  38. return rename(src, dest, overwrite, cb)
  39. })
  40. }
  41. pathExists(dest, (err, destExists) => {
  42. if (err) return cb(err)
  43. if (destExists) return cb(new Error('dest already exists.'))
  44. return rename(src, dest, overwrite, cb)
  45. })
  46. }
  47. function rename (src, dest, overwrite, cb) {
  48. fs.rename(src, dest, err => {
  49. if (!err) return cb()
  50. if (err.code !== 'EXDEV') return cb(err)
  51. return moveAcrossDevice(src, dest, overwrite, cb)
  52. })
  53. }
  54. function moveAcrossDevice (src, dest, overwrite, cb) {
  55. const opts = {
  56. overwrite,
  57. errorOnExist: true
  58. }
  59. copy(src, dest, opts, err => {
  60. if (err) return cb(err)
  61. return remove(src, cb)
  62. })
  63. }
  64. module.exports = move