Version 1
[yaffs-website] / node_modules / fs-extra / lib / copy / ncp.js
diff --git a/node_modules/fs-extra/lib/copy/ncp.js b/node_modules/fs-extra/lib/copy/ncp.js
new file mode 100644 (file)
index 0000000..a951004
--- /dev/null
@@ -0,0 +1,232 @@
+// imported from ncp (this is temporary, will rewrite)
+
+var fs = require('graceful-fs')
+var path = require('path')
+var utimes = require('../util/utimes')
+
+function ncp (source, dest, options, callback) {
+  if (!callback) {
+    callback = options
+    options = {}
+  }
+
+  var basePath = process.cwd()
+  var currentPath = path.resolve(basePath, source)
+  var targetPath = path.resolve(basePath, dest)
+
+  var filter = options.filter
+  var transform = options.transform
+  var clobber = options.clobber !== false // default true
+  var dereference = options.dereference
+  var preserveTimestamps = options.preserveTimestamps === true
+
+  var started = 0
+  var finished = 0
+  var running = 0
+
+  var errored = false
+
+  startCopy(currentPath)
+
+  function startCopy (source) {
+    started++
+    if (filter) {
+      if (filter instanceof RegExp) {
+        console.warn('Warning: fs-extra: Passing a RegExp filter is deprecated, use a function')
+        if (!filter.test(source)) {
+          return doneOne(true)
+        }
+      } else if (typeof filter === 'function') {
+        if (!filter(source)) {
+          return doneOne(true)
+        }
+      }
+    }
+    return getStats(source)
+  }
+
+  function getStats (source) {
+    var stat = dereference ? fs.stat : fs.lstat
+    running++
+    stat(source, function (err, stats) {
+      if (err) return onError(err)
+
+      // We need to get the mode from the stats object and preserve it.
+      var item = {
+        name: source,
+        mode: stats.mode,
+        mtime: stats.mtime, // modified time
+        atime: stats.atime, // access time
+        stats: stats // temporary
+      }
+
+      if (stats.isDirectory()) {
+        return onDir(item)
+      } else if (stats.isFile() || stats.isCharacterDevice() || stats.isBlockDevice()) {
+        return onFile(item)
+      } else if (stats.isSymbolicLink()) {
+        // Symlinks don't really need to know about the mode.
+        return onLink(source)
+      }
+    })
+  }
+
+  function onFile (file) {
+    var target = file.name.replace(currentPath, targetPath.replace('$', '$$$$')) // escapes '$' with '$$'
+    isWritable(target, function (writable) {
+      if (writable) {
+        copyFile(file, target)
+      } else {
+        if (clobber) {
+          rmFile(target, function () {
+            copyFile(file, target)
+          })
+        } else {
+          var err = new Error('EEXIST: ' + target + ' already exists.')
+          err.code = 'EEXIST'
+          err.errno = -17
+          err.path = target
+          onError(err)
+        }
+      }
+    })
+  }
+
+  function copyFile (file, target) {
+    var readStream = fs.createReadStream(file.name)
+    var writeStream = fs.createWriteStream(target, { mode: file.mode })
+
+    readStream.on('error', onError)
+    writeStream.on('error', onError)
+
+    if (transform) {
+      transform(readStream, writeStream, file)
+    } else {
+      writeStream.on('open', function () {
+        readStream.pipe(writeStream)
+      })
+    }
+
+    writeStream.once('finish', function () {
+      fs.chmod(target, file.mode, function (err) {
+        if (err) return onError(err)
+        if (preserveTimestamps) {
+          utimes.utimesMillis(target, file.atime, file.mtime, function (err) {
+            if (err) return onError(err)
+            return doneOne()
+          })
+        } else {
+          doneOne()
+        }
+      })
+    })
+  }
+
+  function rmFile (file, done) {
+    fs.unlink(file, function (err) {
+      if (err) return onError(err)
+      return done()
+    })
+  }
+
+  function onDir (dir) {
+    var target = dir.name.replace(currentPath, targetPath.replace('$', '$$$$')) // escapes '$' with '$$'
+    isWritable(target, function (writable) {
+      if (writable) {
+        return mkDir(dir, target)
+      }
+      copyDir(dir.name)
+    })
+  }
+
+  function mkDir (dir, target) {
+    fs.mkdir(target, dir.mode, function (err) {
+      if (err) return onError(err)
+      // despite setting mode in fs.mkdir, doesn't seem to work
+      // so we set it here.
+      fs.chmod(target, dir.mode, function (err) {
+        if (err) return onError(err)
+        copyDir(dir.name)
+      })
+    })
+  }
+
+  function copyDir (dir) {
+    fs.readdir(dir, function (err, items) {
+      if (err) return onError(err)
+      items.forEach(function (item) {
+        startCopy(path.join(dir, item))
+      })
+      return doneOne()
+    })
+  }
+
+  function onLink (link) {
+    var target = link.replace(currentPath, targetPath)
+    fs.readlink(link, function (err, resolvedPath) {
+      if (err) return onError(err)
+      checkLink(resolvedPath, target)
+    })
+  }
+
+  function checkLink (resolvedPath, target) {
+    if (dereference) {
+      resolvedPath = path.resolve(basePath, resolvedPath)
+    }
+    isWritable(target, function (writable) {
+      if (writable) {
+        return makeLink(resolvedPath, target)
+      }
+      fs.readlink(target, function (err, targetDest) {
+        if (err) return onError(err)
+
+        if (dereference) {
+          targetDest = path.resolve(basePath, targetDest)
+        }
+        if (targetDest === resolvedPath) {
+          return doneOne()
+        }
+        return rmFile(target, function () {
+          makeLink(resolvedPath, target)
+        })
+      })
+    })
+  }
+
+  function makeLink (linkPath, target) {
+    fs.symlink(linkPath, target, function (err) {
+      if (err) return onError(err)
+      return doneOne()
+    })
+  }
+
+  function isWritable (path, done) {
+    fs.lstat(path, function (err) {
+      if (err) {
+        if (err.code === 'ENOENT') return done(true)
+        return done(false)
+      }
+      return done(false)
+    })
+  }
+
+  function onError (err) {
+    // ensure callback is defined & called only once:
+    if (!errored && callback !== undefined) {
+      errored = true
+      return callback(err)
+    }
+  }
+
+  function doneOne (skipped) {
+    if (!skipped) running--
+    finished++
+    if ((started === finished) && (running === 0)) {
+      if (callback !== undefined) {
+        return callback(null)
+      }
+    }
+  }
+}
+
+module.exports = ncp