| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 | 'use strict'module.exports = copymodule.exports.item = copyItemmodule.exports.recurse = recurseDirmodule.exports.symlink = copySymlinkmodule.exports.file = copyFilevar nodeFs = require('fs')var path = require('path')var validate = require('aproba')var stockWriteStreamAtomic = require('fs-write-stream-atomic')var mkdirp = require('mkdirp')var rimraf = require('rimraf')var isWindows = require('./is-windows')var RunQueue = require('run-queue')var extend = Object.assign || require('util')._extendfunction promisify (Promise, fn) {  return function () {    var args = [].slice.call(arguments)    return new Promise(function (resolve, reject) {      return fn.apply(null, args.concat(function (err, value) {        if (err) {          reject(err)        } else {          resolve(value)        }      }))    })  }}function copy (from, to, opts) {  validate('SSO|SS', arguments)  opts = extend({}, opts || {})  var Promise = opts.Promise || global.Promise  var fs = opts.fs || nodeFs  if (opts.isWindows == null) opts.isWindows = isWindows  if (!opts.Promise) opts.Promise = Promise  if (!opts.fs) opts.fs = fs  if (!opts.recurseWith) opts.recurseWith = copyItem  if (!opts.lstat) opts.lstat = promisify(opts.Promise, fs.lstat)  if (!opts.stat) opts.stat = promisify(opts.Promise, fs.stat)  if (!opts.chown) opts.chown = promisify(opts.Promise, fs.chown)  if (!opts.readdir) opts.readdir = promisify(opts.Promise, fs.readdir)  if (!opts.readlink) opts.readlink = promisify(opts.Promise, fs.readlink)  if (!opts.symlink) opts.symlink = promisify(opts.Promise, fs.symlink)  if (!opts.chmod) opts.chmod = promisify(opts.Promise, fs.chmod)  opts.top = from  opts.mkdirpAsync = promisify(opts.Promise, mkdirp)  var rimrafAsync = promisify(opts.Promise, rimraf)  var queue = new RunQueue({    maxConcurrency: opts.maxConcurrency,    Promise: Promise  })  opts.queue = queue  queue.add(0, copyItem, [from, to, opts])  return queue.run().catch(function (err) {    // if the target already exists don't clobber it    if (err.code === 'EEXIST' || err.code === 'EPERM') {      return passThroughError()    } else {      return remove(to).then(passThroughError, passThroughError)    }    function passThroughError () {      return Promise.reject(err)    }  })  function remove (target) {    var opts = {      unlink: fs.unlink,      chmod: fs.chmod,      stat: fs.stat,      lstat: fs.lstat,      rmdir: fs.rmdir,      readdir: fs.readdir,      glob: false    }    return rimrafAsync(target, opts)  }}function copyItem (from, to, opts) {  validate('SSO', [from, to, opts])  var fs = opts.fs || nodeFs  var Promise = opts.Promise || global.Promise  var lstat = opts.lstat || promisify(Promise, fs.lstat)  return lstat(to).then(function () {    return Promise.reject(eexists(from, to))  }, function (err) {    if (err && err.code !== 'ENOENT') return Promise.reject(err)    return lstat(from)  }).then(function (fromStat) {    var cmdOpts = extend(extend({}, opts), fromStat)    if (fromStat.isDirectory()) {      return recurseDir(from, to, cmdOpts)    } else if (fromStat.isSymbolicLink()) {      opts.queue.add(1, copySymlink, [from, to, cmdOpts])    } else if (fromStat.isFile()) {      return copyFile(from, to, cmdOpts)    } else if (fromStat.isBlockDevice()) {      return Promise.reject(eunsupported(from + " is a block device, and we don't know how to copy those."))    } else if (fromStat.isCharacterDevice()) {      return Promise.reject(eunsupported(from + " is a character device, and we don't know how to copy those."))    } else if (fromStat.isFIFO()) {      return Promise.reject(eunsupported(from + " is a FIFO, and we don't know how to copy those."))    } else if (fromStat.isSocket()) {      return Promise.reject(eunsupported(from + " is a socket, and we don't know how to copy those."))    } else {      return Promise.reject(eunsupported("We can't tell what " + from + " is and so we can't copy it."))    }  })}function recurseDir (from, to, opts) {  validate('SSO', [from, to, opts])  var recurseWith = opts.recurseWith || copyItem  var fs = opts.fs || nodeFs  var chown = opts.chown || promisify(Promise, fs.chown)  var readdir = opts.readdir || promisify(Promise, fs.readdir)  var mkdirpAsync = opts.mkdirpAsync || promisify(Promise, mkdirp)  return mkdirpAsync(to, {fs: fs, mode: opts.mode}).then(function () {    var getuid = opts.getuid || process.getuid    if (getuid && opts.uid != null && getuid() === 0) {      return chown(to, opts.uid, opts.gid)    }  }).then(function () {    return readdir(from)  }).then(function (files) {    files.forEach(function (file) {      opts.queue.add(0, recurseWith, [path.join(from, file), path.join(to, file), opts])    })  })}function copySymlink (from, to, opts) {  validate('SSO', [from, to, opts])  var fs = opts.fs || nodeFs  var readlink = opts.readlink || promisify(Promise, fs.readlink)  var stat = opts.stat || promisify(Promise, fs.symlink)  var symlink = opts.symlink || promisify(Promise, fs.symlink)  var Promise = opts.Promise || global.Promise  return readlink(from).then(function (fromDest) {    var absoluteDest = path.resolve(path.dirname(from), fromDest)    // Treat absolute paths that are inside the tree we're    // copying as relative. This necessary to properly support junctions    // on windows (which are always absolute) but is also DWIM with symlinks.    var relativeDest = path.relative(opts.top, absoluteDest)    var linkFrom = relativeDest.substr(0, 2) === '..' ? fromDest : path.relative(path.dirname(from), absoluteDest)    if (opts.isWindows) {      return stat(absoluteDest).catch(function () { return null }).then(function (destStat) {        var isDir = destStat && destStat.isDirectory()        var type = isDir ? 'dir' : 'file'        return symlink(linkFrom, to, type).catch(function (err) {          if (type === 'dir') {            return symlink(linkFrom, to, 'junction')          } else {            return Promise.reject(err)          }        })      })    } else {      return symlink(linkFrom, to)    }  })}function copyFile (from, to, opts) {  validate('SSO', [from, to, opts])  var fs = opts.fs || nodeFs  var writeStreamAtomic = opts.writeStreamAtomic || stockWriteStreamAtomic  var Promise = opts.Promise || global.Promise  var chmod = opts.chmod || promisify(Promise, fs.chmod)  var writeOpts = {}  var getuid = opts.getuid || process.getuid  if (getuid && opts.uid != null && getuid() === 0) {    writeOpts.chown = {      uid: opts.uid,      gid: opts.gid    }  }  return new Promise(function (resolve, reject) {    var errored = false    function onError (err) {      errored = true      reject(err)    }    fs.createReadStream(from)      .once('error', onError)      .pipe(writeStreamAtomic(to, writeOpts))      .once('error', onError)      .once('close', function () {        if (errored) return        if (opts.mode != null) {          resolve(chmod(to, opts.mode))        } else {          resolve()        }      })  })}function eexists (from, to) {  var err = new Error('Could not move ' + from + ' to ' + to + ': destination already exists.')  err.code = 'EEXIST'  return err}function eunsupported (msg) {  var err = new Error(msg)  err.code = 'EUNSUPPORTED'  return err}
 |