123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235 |
- // 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 overwrite = options.overwrite
- // If overwrite is undefined, use clobber, otherwise default to true:
- if (overwrite === undefined) overwrite = options.clobber
- if (overwrite === undefined) overwrite = true
- var errorOnExist = options.errorOnExist
- 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, dest)) {
- 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 (overwrite) {
- rmFile(target, function () {
- copyFile(file, target)
- })
- } else if (errorOnExist) {
- onError(new Error(target + ' already exists'))
- } else {
- doneOne()
- }
- }
- })
- }
-
- 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('close', 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
|