move.js 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. 'use strict'
  2. module.exports = move
  3. var nodeFs = require('fs')
  4. var rimraf = require('rimraf')
  5. var validate = require('aproba')
  6. var copy = require('copy-concurrently')
  7. var RunQueue = require('run-queue')
  8. var extend = Object.assign || require('util')._extend
  9. function promisify (Promise, fn) {
  10. return function () {
  11. var args = [].slice.call(arguments)
  12. return new Promise(function (resolve, reject) {
  13. return fn.apply(null, args.concat(function (err, value) {
  14. if (err) {
  15. reject(err)
  16. } else {
  17. resolve(value)
  18. }
  19. }))
  20. })
  21. }
  22. }
  23. function move (from, to, opts) {
  24. validate('SSO|SS', arguments)
  25. opts = extend({}, opts || {})
  26. var Promise = opts.Promise || global.Promise
  27. var fs = opts.fs || nodeFs
  28. var rimrafAsync = promisify(Promise, rimraf)
  29. var renameAsync = promisify(Promise, fs.rename)
  30. opts.top = from
  31. var queue = new RunQueue({
  32. maxConcurrency: opts.maxConcurrency,
  33. Promise: Promise
  34. })
  35. opts.queue = queue
  36. opts.recurseWith = rename
  37. queue.add(0, rename, [from, to, opts])
  38. return queue.run().then(function () {
  39. return remove(from)
  40. }, function (err) {
  41. // if the target already exists don't clobber it
  42. if (err.code === 'EEXIST' || err.code === 'EPERM') {
  43. return passThroughError()
  44. } else {
  45. return remove(to).then(passThroughError, passThroughError)
  46. }
  47. function passThroughError () {
  48. return Promise.reject(err)
  49. }
  50. })
  51. function remove (target) {
  52. var opts = {
  53. unlink: fs.unlink,
  54. chmod: fs.chmod,
  55. stat: fs.stat,
  56. lstat: fs.lstat,
  57. rmdir: fs.rmdir,
  58. readdir: fs.readdir,
  59. glob: false
  60. }
  61. return rimrafAsync(target, opts)
  62. }
  63. function rename (from, to, opts, done) {
  64. return renameAsync(from, to).catch(function (err) {
  65. if (err.code !== 'EXDEV') {
  66. return Promise.reject(err)
  67. } else {
  68. return remove(to).then(function () {
  69. return copy.item(from, to, opts)
  70. })
  71. }
  72. })
  73. }
  74. }