// imported from ncp (this is temporary, will rewrite) var fs = require('graceful-fs') var path = require('path') function ncp (source, dest, options, callback) { var cback = callback if (!callback) { cback = 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 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 cb(true) } } else if (typeof filter === 'function') { if (!filter(source)) { return cb(true) } } } return getStats(source) } function getStats(source) { var defer = global.setImmediate || process.nextTick var stat = dereference ? fs.stat : fs.lstat if (running >= limit) { return defer(function () { getStats(source) }) } running++ stat(source, function (err, stats) { var item = {} if (err) { return onError(err) } // We need to get the mode from the stats object and preserve it. item.name = source item.mode = stats.mode item.mtime = stats.mtime //modified time item.atime = stats.atime //access time if (stats.isDirectory()) { return onDir(item) } else if (stats.isFile()) { 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 { cb() } } }) } function copyFile(file, target) { var readStream = fs.createReadStream(file.name), 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) }) } //presumably old node then var eventName = global.setImmediate ? 'finish' : 'close' writeStream.once(eventName, function() { cb() }) } 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) } 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 cb() }) } 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 cb() } return rmFile(target, function () { makeLink(resolvedPath, target) }) }) }) } function makeLink(linkPath, target) { fs.symlink(linkPath, target, function (err) { if (err) { return onError(err) } return cb() }) } 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 cback(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 cb() } function cb(skipped) { if (!skipped) running-- finished++ if ((started === finished) && (running === 0)) { if (cback !== undefined ) { return errs ? cback(errs) : cback(null) } } } } // todo, make this just export ncp module.exports.ncp = ncp