1 // imported from ncp (this is temporary, will rewrite)
3 var fs = require('graceful-fs')
4 var path = require('path')
5 var utimes = require('../util/utimes')
7 function ncp (source, dest, options, callback) {
13 var basePath = process.cwd()
14 var currentPath = path.resolve(basePath, source)
15 var targetPath = path.resolve(basePath, dest)
17 var filter = options.filter
18 var transform = options.transform
19 var clobber = options.clobber !== false // default true
20 var dereference = options.dereference
21 var preserveTimestamps = options.preserveTimestamps === true
29 startCopy(currentPath)
31 function startCopy (source) {
34 if (filter instanceof RegExp) {
35 console.warn('Warning: fs-extra: Passing a RegExp filter is deprecated, use a function')
36 if (!filter.test(source)) {
39 } else if (typeof filter === 'function') {
40 if (!filter(source)) {
45 return getStats(source)
48 function getStats (source) {
49 var stat = dereference ? fs.stat : fs.lstat
51 stat(source, function (err, stats) {
52 if (err) return onError(err)
54 // We need to get the mode from the stats object and preserve it.
58 mtime: stats.mtime, // modified time
59 atime: stats.atime, // access time
60 stats: stats // temporary
63 if (stats.isDirectory()) {
65 } else if (stats.isFile() || stats.isCharacterDevice() || stats.isBlockDevice()) {
67 } else if (stats.isSymbolicLink()) {
68 // Symlinks don't really need to know about the mode.
74 function onFile (file) {
75 var target = file.name.replace(currentPath, targetPath.replace('$', '$$$$')) // escapes '$' with '$$'
76 isWritable(target, function (writable) {
78 copyFile(file, target)
81 rmFile(target, function () {
82 copyFile(file, target)
85 var err = new Error('EEXIST: ' + target + ' already exists.')
95 function copyFile (file, target) {
96 var readStream = fs.createReadStream(file.name)
97 var writeStream = fs.createWriteStream(target, { mode: file.mode })
99 readStream.on('error', onError)
100 writeStream.on('error', onError)
103 transform(readStream, writeStream, file)
105 writeStream.on('open', function () {
106 readStream.pipe(writeStream)
110 writeStream.once('finish', function () {
111 fs.chmod(target, file.mode, function (err) {
112 if (err) return onError(err)
113 if (preserveTimestamps) {
114 utimes.utimesMillis(target, file.atime, file.mtime, function (err) {
115 if (err) return onError(err)
125 function rmFile (file, done) {
126 fs.unlink(file, function (err) {
127 if (err) return onError(err)
132 function onDir (dir) {
133 var target = dir.name.replace(currentPath, targetPath.replace('$', '$$$$')) // escapes '$' with '$$'
134 isWritable(target, function (writable) {
136 return mkDir(dir, target)
142 function mkDir (dir, target) {
143 fs.mkdir(target, dir.mode, function (err) {
144 if (err) return onError(err)
145 // despite setting mode in fs.mkdir, doesn't seem to work
146 // so we set it here.
147 fs.chmod(target, dir.mode, function (err) {
148 if (err) return onError(err)
154 function copyDir (dir) {
155 fs.readdir(dir, function (err, items) {
156 if (err) return onError(err)
157 items.forEach(function (item) {
158 startCopy(path.join(dir, item))
164 function onLink (link) {
165 var target = link.replace(currentPath, targetPath)
166 fs.readlink(link, function (err, resolvedPath) {
167 if (err) return onError(err)
168 checkLink(resolvedPath, target)
172 function checkLink (resolvedPath, target) {
174 resolvedPath = path.resolve(basePath, resolvedPath)
176 isWritable(target, function (writable) {
178 return makeLink(resolvedPath, target)
180 fs.readlink(target, function (err, targetDest) {
181 if (err) return onError(err)
184 targetDest = path.resolve(basePath, targetDest)
186 if (targetDest === resolvedPath) {
189 return rmFile(target, function () {
190 makeLink(resolvedPath, target)
196 function makeLink (linkPath, target) {
197 fs.symlink(linkPath, target, function (err) {
198 if (err) return onError(err)
203 function isWritable (path, done) {
204 fs.lstat(path, function (err) {
206 if (err.code === 'ENOENT') return done(true)
213 function onError (err) {
214 // ensure callback is defined & called only once:
215 if (!errored && callback !== undefined) {
221 function doneOne (skipped) {
222 if (!skipped) running--
224 if ((started === finished) && (running === 0)) {
225 if (callback !== undefined) {
226 return callback(null)