Created
December 20, 2011 07:17
-
-
Save jiangmiao/1500634 to your computer and use it in GitHub Desktop.
copy-dir
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function() { | |
var confirm, copy, copyDir, copyFile, copyFileByLoop, copyFileByPipe, copyFileByPump, fs, path, print, puts, readline, strError, util; | |
fs = require('fs'); | |
path = require('path'); | |
util = require('util'); | |
readline = require('readline').createInterface(process.stdin, process.stdout); | |
puts = function() { | |
return console.info.apply(console, arguments); | |
}; | |
print = function() { | |
return process.stdout.write.apply(process.stdout, arguments); | |
}; | |
strError = function(err) { | |
if (err) { | |
return "\033[31mERROR!!! " + err.message + "\033[0m"; | |
} else { | |
return "\033[32mdone.\033[0m"; | |
} | |
}; | |
confirm = function(text, cb) { | |
var once; | |
return (once = function() { | |
var _this = this; | |
return readline.question(text, function(_$$_answer) { | |
var answer; | |
answer = _$$_answer; | |
if (answer.match(/^(yes|y)$/i)) { | |
return cb(true); | |
} else if (answer.match(/^(no|n)$/i)) { | |
return cb(false); | |
} else { | |
return once(); | |
} | |
}); | |
})(); | |
}; | |
copyFileByPump = function(src, dest, cb) { | |
var readStream, writeStream; | |
readStream = fs.createReadStream(src); | |
writeStream = fs.createWriteStream(dest); | |
writeStream.end = function() { | |
if (this.fd != null) { | |
return fs.WriteStream.prototype.end.apply(this, arguments); | |
} | |
}; | |
return util.pump(readStream, writeStream, cb); | |
}; | |
copyFileByLoop = function(src, dest, cb) { | |
var dest_fd, done, src_fd, | |
_this = this; | |
src_fd = dest_fd = null; | |
done = function(err) { | |
if (src_fd != null) fs.close(src_fd); | |
if (dest_fd != null) fs.close(dest_fd); | |
return cb(err); | |
}; | |
return fs.open(src, "r", function(_$$_err, _$$_src_fd) { | |
var err; | |
err = _$$_err; | |
src_fd = _$$_src_fd; | |
if (err) return done(err); | |
return fs.open(dest, "w", function(_$$_err, _$$_dest_fd) { | |
var buffer, buffer_size, once; | |
err = _$$_err; | |
dest_fd = _$$_dest_fd; | |
if (err) return done(err); | |
buffer_size = 4 * 4096; | |
buffer = new Buffer(buffer_size); | |
return (once = function() { | |
var _this = this; | |
return fs.read(src_fd, buffer, 0, buffer_size, null, function(_$$_err, _$$_bytesRead) { | |
var bytesRead; | |
err = _$$_err; | |
bytesRead = _$$_bytesRead; | |
if (err || bytesRead === 0) return done(err); | |
return fs.write(dest_fd, buffer, 0, bytesRead, null, function(_$$_err) { | |
err = _$$_err; | |
if (err) return done(err); | |
return once(); | |
}); | |
}); | |
})(); | |
}); | |
}); | |
}; | |
copyFileByPipe = function(src, dest, cb) { | |
var called, done, readStream, writeStream; | |
readStream = fs.createReadStream(src); | |
writeStream = fs.createWriteStream(dest); | |
called = false; | |
done = function(err) { | |
if (called) return; | |
called = true; | |
if (err) { | |
readStream.destroy(); | |
writeStream.destroy(); | |
} | |
return cb(err); | |
}; | |
readStream.on('error', done); | |
writeStream.on('error', done); | |
writeStream.on('close', done); | |
return readStream.pipe(writeStream); | |
}; | |
copyFile = function(src, dest, cb) { | |
var _this = this; | |
return path.exists(dest, function(_$$_exists) { | |
var exists, _asfn0; | |
exists = _$$_exists; | |
_asfn0 = function() { | |
print("Copying \"" + src + "\" to \"" + dest + "\" ... "); | |
return copyFileByLoop(src, dest, function(_$$_err) { | |
var err; | |
err = _$$_err; | |
puts(strError(err)); | |
return cb(); | |
}); | |
}; | |
if (exists) { | |
return confirm("File \"" + dest + "\" exists, overwrite? (yes/no) > ", function(_$$_overwrite) { | |
var overwrite; | |
overwrite = _$$_overwrite; | |
if (!overwrite) return cb(); | |
return _asfn0(); | |
}); | |
} else { | |
return _asfn0(); | |
} | |
}); | |
}; | |
copyDir = function(src, dest, cb) { | |
var _this = this; | |
return path.exists(dest, function(_$$_exists) { | |
var exists, _asfn1; | |
exists = _$$_exists; | |
_asfn1 = function() { | |
return fs.readdir(src, function(_$$_err, _$$_files) { | |
var err, files, once; | |
err = _$$_err; | |
files = _$$_files; | |
if (err) { | |
puts(strError(new Error("Cannot open directory \"" + src + "\""))); | |
return cb(); | |
} | |
return (once = function() { | |
var file, subdest, subsrc, | |
_this = this; | |
file = files.shift(); | |
if (!file) return cb(); | |
subsrc = path.join(src, file); | |
subdest = path.join(dest, file); | |
return copy(subsrc, subdest, function() { | |
return once(); | |
}); | |
})(); | |
}); | |
}; | |
if (!exists) { | |
print("Creating directory \"" + dest + "\" ... "); | |
return fs.mkdir(dest, function(_$$_err) { | |
var err; | |
err = _$$_err; | |
puts(strError(err)); | |
if (err) return cb(); | |
return _asfn1(); | |
}); | |
} else { | |
return _asfn1(); | |
} | |
}); | |
}; | |
copy = function(src, dest, cb) { | |
var _this = this; | |
return fs.stat(src, function(_$$_err, _$$_src_stat) { | |
var err, src_stat; | |
err = _$$_err; | |
src_stat = _$$_src_stat; | |
if (err) { | |
puts(strError(err)); | |
return cb(); | |
} | |
if (src_stat.isFile()) { | |
return copyFile(src, dest, cb); | |
} else { | |
return copyDir(src, dest, cb); | |
} | |
}); | |
}; | |
copy(process.argv[2], process.argv[3], function() { | |
puts('Finished.'); | |
readline.close(); | |
return process.stdin.destroy(); | |
}); | |
}).call(this); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 本代码是 @老赵 的[copy-dir](https://github.com/JeffreyZhao/jscex/blob/master/doc/async/samples/copy-dir-cn.md)的ToffeeScript实现 | |
# Jscex版本位于[Jscex版copy-dir](https://github.com/JeffreyZhao/jscex/blob/master/samples/async/copy-dir.js) | |
# | |
# 直接感觉就是异常处理上,Jscex由于支持异常大大节省的错误的判断次数。另外全代码几乎都可以用同步的结构写异步,异常的方便。 | |
# | |
# ToffeeScript代码从理解上基本等同与不使用任何类库原生JavaScript,只是更改了回调函数的位置。由于CoffeeScript的语法方便,异步写起来也不冗长,只是出口有点多。 | |
fs = require :fs | |
path = require :path | |
util = require :util | |
readline = require(:readline).createInterface process.stdin, process.stdout | |
puts = -> console.info.apply console, arguments | |
print = -> process.stdout.write.apply process.stdout, arguments | |
strError = (err) -> if err then "\033[31mERROR!!! #{err.message}\033[0m" else "\033[32mdone.\033[0m" | |
# cb = (bool) -> | |
confirm = (text, cb) -> | |
do once = -> | |
answer = readline.question! text | |
if answer.match /^(yes|y)$/i | |
cb(true) | |
else if answer.match /^(no|n)$/i | |
cb(false) | |
else | |
once() | |
# cb = (err) -> | |
copyFileByPump = (src, dest, cb) -> | |
readStream = fs.createReadStream src | |
writeStream = fs.createWriteStream dest | |
# 用util.pump, 如果src为0字节且dest不可写, 会出uncaughtException, 弃用 | |
writeStream.end = -> | |
if @fd? | |
fs.WriteStream::end.apply @, arguments | |
util.pump readStream, writeStream, cb | |
# 比起 util.pump 用传统的的read + write 更可控些 | |
# cb = (err) -> | |
copyFileByLoop = (src, dest, cb) -> | |
src_fd = dest_fd = null | |
done = (err) -> | |
fs.close src_fd if src_fd? | |
fs.close dest_fd if dest_fd? | |
cb(err) | |
err, src_fd = fs.open! src, "r" | |
return done(err) if err | |
err, dest_fd = fs.open! dest, "w" | |
return done(err) if err | |
buffer_size = 4*4096 | |
buffer = new Buffer(buffer_size) | |
do once = -> | |
err, bytesRead = fs.read! src_fd, buffer, 0, buffer_size, null | |
return done(err) if err || bytesRead == 0 | |
err = fs.write! dest_fd, buffer, 0, bytesRead, null | |
return done(err) if err | |
once() | |
# cb = (err) -> | |
copyFileByPipe = (src, dest, cb) -> | |
readStream = fs.createReadStream src | |
writeStream = fs.createWriteStream dest | |
called = false | |
done = (err) -> | |
return if called | |
called = true | |
if err | |
readStream.destroy() | |
writeStream.destroy() | |
cb(err) | |
readStream.on :error, done | |
writeStream.on :error, done | |
writeStream.on :close, done | |
readStream.pipe writeStream | |
# cb = -> | |
copyFile = (src, dest, cb) -> | |
exists = path.exists! dest | |
if! exists | |
overwrite = confirm! "File \"#{dest}\" exists, overwrite? (yes/no) > " | |
return cb() unless overwrite | |
print "Copying \"#{src}\" to \"#{dest}\" ... " | |
err = copyFileByLoop! src, dest | |
# err = copyFileByPipe! src, dest | |
puts strError(err) | |
cb() | |
# cb = -> | |
copyDir = (src, dest, cb) -> | |
exists = path.exists! dest | |
unless! exists | |
print "Creating directory \"#{dest}\" ... " | |
err = fs.mkdir! dest | |
puts strError(err) | |
return cb() if err | |
err, files = fs.readdir! src | |
if err | |
puts strError new Error "Cannot open directory \"#{src}\"" | |
return cb() | |
do once = -> | |
file = files.shift() | |
return cb() unless file | |
subsrc = path.join src, file | |
subdest = path.join dest, file | |
copy! subsrc, subdest | |
once() | |
# cb = -> | |
copy = (src, dest, cb) -> | |
err, src_stat = fs.stat! src | |
if err | |
puts strError(err) | |
return cb() | |
if src_stat.isFile() | |
copyFile src, dest, cb | |
else | |
copyDir src, dest, cb | |
copy process.argv[2], process.argv[3], -> | |
puts 'Finished.' | |
readline.close() | |
process.stdin.destroy() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment