// 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 var dereference = options.dereference var preserveTimestamps = options.preserveTimestamps === true var errs = null var started = 0 var finished = 0 var running = 0 // this is pretty useless now that we're using graceful-fs // consider removing var limit = options.limit || 512 startCopy(currentPath) function startCopy (source) { started++ if (filter) { if (filter instanceof RegExp) { 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 if (running >= limit) { return setImmediate(function () { getStats(source) }) } 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) isWritable(target, function (writable) { if (writable) { copyFile(file, target) } else { if (clobber) { rmFile(target, function () { copyFile(file, target) }) } 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('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) 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) { if (options.stopOnError) { return callback(err) } else if (!errs && options.errs) { errs = fs.createWriteStream(options.errs) } else if (!errs) { errs = [] } if (typeof errs.write === 'undefined') { errs.push(err) } else { errs.write(err.stack + '\n\n') } return doneOne() } function doneOne (skipped) { if (!skipped) running-- finished++ if ((started === finished) && (running === 0)) { if (callback !== undefined) { return errs ? callback(errs) : callback(null) } } } } module.exports = ncp