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