mirror of
https://github.com/nunocoracao/blowfish.git
synced 2026-01-30 15:31:52 +00:00
config redirect
This commit is contained in:
+4
@@ -0,0 +1,4 @@
|
||||
node_modules
|
||||
.*.sw[op]
|
||||
.DS_Store
|
||||
test/*fixtures/out
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
language: node_js
|
||||
|
||||
node_js:
|
||||
- 0.8
|
||||
- "0.10"
|
||||
- "0.11"
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
# MIT License
|
||||
|
||||
###Copyright (C) 2011 by Charlie McConnell
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
# ncp - Asynchronous recursive file & directory copying
|
||||
|
||||
[](http://travis-ci.org/AvianFlu/ncp)
|
||||
|
||||
Think `cp -r`, but pure node, and asynchronous. `ncp` can be used both as a CLI tool and programmatically.
|
||||
|
||||
## Command Line usage
|
||||
|
||||
Usage is simple: `ncp [source] [dest] [--limit=concurrency limit]
|
||||
[--filter=filter] --stopOnErr`
|
||||
|
||||
The 'filter' is a Regular Expression - matched files will be copied.
|
||||
|
||||
The 'concurrency limit' is an integer that represents how many pending file system requests `ncp` has at a time.
|
||||
|
||||
'stoponerr' is a boolean flag that will tell `ncp` to stop immediately if any
|
||||
errors arise, rather than attempting to continue while logging errors. The default behavior is to complete as many copies as possible, logging errors along the way.
|
||||
|
||||
If there are no errors, `ncp` will output `done.` when complete. If there are errors, the error messages will be logged to `stdout` and to `./ncp-debug.log`, and the copy operation will attempt to continue.
|
||||
|
||||
## Programmatic usage
|
||||
|
||||
Programmatic usage of `ncp` is just as simple. The only argument to the completion callback is a possible error.
|
||||
|
||||
```javascript
|
||||
var ncp = require('ncp').ncp;
|
||||
|
||||
ncp.limit = 16;
|
||||
|
||||
ncp(source, destination, function (err) {
|
||||
if (err) {
|
||||
return console.error(err);
|
||||
}
|
||||
console.log('done!');
|
||||
});
|
||||
```
|
||||
|
||||
You can also call ncp like `ncp(source, destination, options, callback)`.
|
||||
`options` should be a dictionary. Currently, such options are available:
|
||||
|
||||
* `options.filter` - a `RegExp` instance, against which each file name is
|
||||
tested to determine whether to copy it or not, or a function taking single
|
||||
parameter: copied file name, returning `true` or `false`, determining
|
||||
whether to copy file or not.
|
||||
|
||||
* `options.transform` - a function: `function (read, write) { read.pipe(write) }`
|
||||
used to apply streaming transforms while copying.
|
||||
|
||||
* `options.clobber` - boolean=true. if set to false, `ncp` will not overwrite
|
||||
destination files that already exist.
|
||||
|
||||
* `options.dereference` - boolean=false. If set to true, `ncp` will follow symbolic
|
||||
links. For example, a symlink in the source tree pointing to a regular file
|
||||
will become a regular file in the destination tree. Broken symlinks will result in
|
||||
errors.
|
||||
|
||||
* `options.stopOnErr` - boolean=false. If set to true, `ncp` will behave like `cp -r`,
|
||||
and stop on the first error it encounters. By default, `ncp` continues copying, logging all
|
||||
errors and returning an array.
|
||||
|
||||
* `options.errs` - stream. If `options.stopOnErr` is `false`, a stream can be provided, and errors will be written to this stream.
|
||||
|
||||
Please open an issue if any bugs arise. As always, I accept (working) pull requests, and refunds are available at `/dev/null`.
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
|
||||
|
||||
|
||||
var ncp = require('../lib/ncp'),
|
||||
args = process.argv.slice(2),
|
||||
source, dest;
|
||||
|
||||
if (args.length < 2) {
|
||||
console.error('Usage: ncp [source] [destination] [--filter=filter] [--limit=concurrency limit]');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// parse arguments the hard way
|
||||
function startsWith(str, prefix) {
|
||||
return str.substr(0, prefix.length) == prefix;
|
||||
}
|
||||
|
||||
var options = {};
|
||||
args.forEach(function (arg) {
|
||||
if (startsWith(arg, "--limit=")) {
|
||||
options.limit = parseInt(arg.split('=', 2)[1], 10);
|
||||
}
|
||||
if (startsWith(arg, "--filter=")) {
|
||||
options.filter = new RegExp(arg.split('=', 2)[1]);
|
||||
}
|
||||
if (startsWith(arg, "--stoponerr")) {
|
||||
options.stopOnErr = true;
|
||||
}
|
||||
});
|
||||
|
||||
ncp.ncp(args[0], args[1], options, function (err) {
|
||||
if (Array.isArray(err)) {
|
||||
console.error('There were errors during the copy.');
|
||||
err.forEach(function (err) {
|
||||
console.error(err.stack || err.message);
|
||||
});
|
||||
process.exit(1);
|
||||
}
|
||||
else if (err) {
|
||||
console.error('An error has occurred.');
|
||||
console.error(err.stack || err.message);
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
+261
@@ -0,0 +1,261 @@
|
||||
var fs = require('fs'),
|
||||
path = require('path');
|
||||
|
||||
module.exports = ncp;
|
||||
ncp.ncp = ncp;
|
||||
|
||||
function ncp (source, dest, options, callback) {
|
||||
var cback = callback;
|
||||
|
||||
if (!callback) {
|
||||
cback = options;
|
||||
options = {};
|
||||
}
|
||||
|
||||
var basePath = process.cwd(),
|
||||
currentPath = path.resolve(basePath, source),
|
||||
targetPath = path.resolve(basePath, dest),
|
||||
filter = options.filter,
|
||||
rename = options.rename,
|
||||
transform = options.transform,
|
||||
clobber = options.clobber !== false,
|
||||
modified = options.modified,
|
||||
dereference = options.dereference,
|
||||
errs = null,
|
||||
started = 0,
|
||||
finished = 0,
|
||||
running = 0,
|
||||
limit = options.limit || ncp.limit || 16;
|
||||
|
||||
limit = (limit < 1) ? 1 : (limit > 512) ? 512 : limit;
|
||||
|
||||
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 stat = dereference ? fs.stat : fs.lstat;
|
||||
if (running >= limit) {
|
||||
return setImmediate(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);
|
||||
if(rename) {
|
||||
target = rename(target);
|
||||
}
|
||||
isWritable(target, function (writable) {
|
||||
if (writable) {
|
||||
return copyFile(file, target);
|
||||
}
|
||||
if(clobber) {
|
||||
rmFile(target, function () {
|
||||
copyFile(file, target);
|
||||
});
|
||||
}
|
||||
if (modified) {
|
||||
var stat = dereference ? fs.stat : fs.lstat;
|
||||
stat(target, function(err, stats) {
|
||||
//if souce modified time greater to target modified time copy file
|
||||
if (file.mtime.getTime()>stats.mtime.getTime())
|
||||
copyFile(file, target);
|
||||
else return cb();
|
||||
});
|
||||
}
|
||||
else {
|
||||
return 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);
|
||||
});
|
||||
}
|
||||
writeStream.once('finish', function() {
|
||||
if (modified) {
|
||||
//target file modified date sync.
|
||||
fs.utimesSync(target, file.atime, file.mtime);
|
||||
cb();
|
||||
}
|
||||
else 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "ncp",
|
||||
"version": "2.0.0",
|
||||
"author": "AvianFlu <charlie@charlieistheman.com>",
|
||||
"description": "Asynchronous recursive file copy utility.",
|
||||
"bin": {
|
||||
"ncp": "./bin/ncp"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mocha": "1.15.x",
|
||||
"rimraf": "1.0.x",
|
||||
"read-dir-files": "0.0.x"
|
||||
},
|
||||
"main": "./lib/ncp.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/AvianFlu/ncp.git"
|
||||
},
|
||||
"keywords": [
|
||||
"cli",
|
||||
"copy"
|
||||
],
|
||||
"license": "MIT",
|
||||
"engine": {
|
||||
"node": ">=0.10"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "mocha -R spec"
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
test3
|
||||
+1
@@ -0,0 +1 @@
|
||||
test3
|
||||
+197
@@ -0,0 +1,197 @@
|
||||
|
||||
|
||||
var assert = require('assert'),
|
||||
fs = require('fs'),
|
||||
path = require('path'),
|
||||
rimraf = require('rimraf'),
|
||||
readDirFiles = require('read-dir-files'),
|
||||
util = require('util'),
|
||||
ncp = require('../').ncp;
|
||||
|
||||
|
||||
|
||||
describe('ncp', function () {
|
||||
describe('regular files and directories', function () {
|
||||
var fixtures = path.join(__dirname, 'regular-fixtures'),
|
||||
src = path.join(fixtures, 'src'),
|
||||
out = path.join(fixtures, 'out');
|
||||
|
||||
before(function (cb) {
|
||||
rimraf(out, function() {
|
||||
ncp(src, out, cb);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when copying a directory of files', function () {
|
||||
it('files are copied correctly', function (cb) {
|
||||
readDirFiles(src, 'utf8', function (srcErr, srcFiles) {
|
||||
readDirFiles(out, 'utf8', function (outErr, outFiles) {
|
||||
assert.ifError(srcErr);
|
||||
assert.deepEqual(srcFiles, outFiles);
|
||||
cb();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when copying files using filter', function () {
|
||||
before(function (cb) {
|
||||
var filter = function(name) {
|
||||
return name.substr(name.length - 1) != 'a';
|
||||
};
|
||||
rimraf(out, function () {
|
||||
ncp(src, out, {filter: filter}, cb);
|
||||
});
|
||||
});
|
||||
|
||||
it('files are copied correctly', function (cb) {
|
||||
readDirFiles(src, 'utf8', function (srcErr, srcFiles) {
|
||||
function filter(files) {
|
||||
for (var fileName in files) {
|
||||
var curFile = files[fileName];
|
||||
if (curFile instanceof Object)
|
||||
return filter(curFile);
|
||||
if (fileName.substr(fileName.length - 1) == 'a')
|
||||
delete files[fileName];
|
||||
}
|
||||
}
|
||||
filter(srcFiles);
|
||||
readDirFiles(out, 'utf8', function (outErr, outFiles) {
|
||||
assert.ifError(outErr);
|
||||
assert.deepEqual(srcFiles, outFiles);
|
||||
cb();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when using clobber=false', function () {
|
||||
it('the copy is completed successfully', function (cb) {
|
||||
ncp(src, out, function() {
|
||||
ncp(src, out, {clobber: false}, function(err) {
|
||||
assert.ifError(err);
|
||||
cb();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when using transform', function () {
|
||||
it('file descriptors are passed correctly', function (cb) {
|
||||
ncp(src, out, {
|
||||
transform: function(read,write,file) {
|
||||
assert.notEqual(file.name, undefined);
|
||||
assert.strictEqual(typeof file.mode,'number');
|
||||
read.pipe(write);
|
||||
}
|
||||
}, cb);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when using rename', function() {
|
||||
it('output files are correctly redirected', function(cb) {
|
||||
ncp(src, out, {
|
||||
rename: function(target) {
|
||||
if(path.basename(target) == 'a') return path.resolve(path.dirname(target), 'z');
|
||||
return target;
|
||||
}
|
||||
}, function(err) {
|
||||
if(err) return cb(err);
|
||||
|
||||
readDirFiles(src, 'utf8', function (srcErr, srcFiles) {
|
||||
readDirFiles(out, 'utf8', function (outErr, outFiles) {
|
||||
assert.ifError(srcErr);
|
||||
assert.deepEqual(srcFiles.a, outFiles.z);
|
||||
cb();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('symlink handling', function () {
|
||||
var fixtures = path.join(__dirname, 'symlink-fixtures'),
|
||||
src = path.join(fixtures, 'src'),
|
||||
out = path.join(fixtures, 'out');
|
||||
|
||||
beforeEach(function (cb) {
|
||||
rimraf(out, cb);
|
||||
});
|
||||
|
||||
it('copies symlinks by default', function (cb) {
|
||||
ncp(src, out, function (err) {
|
||||
if (err) return cb(err);
|
||||
assert.equal(fs.readlinkSync(path.join(out, 'file-symlink')), 'foo');
|
||||
assert.equal(fs.readlinkSync(path.join(out, 'dir-symlink')), 'dir');
|
||||
cb();
|
||||
})
|
||||
});
|
||||
|
||||
it('copies file contents when dereference=true', function (cb) {
|
||||
ncp(src, out, { dereference: true }, function (err) {
|
||||
var fileSymlinkPath = path.join(out, 'file-symlink');
|
||||
assert.ok(fs.lstatSync(fileSymlinkPath).isFile());
|
||||
assert.equal(fs.readFileSync(fileSymlinkPath), 'foo contents');
|
||||
|
||||
var dirSymlinkPath = path.join(out, 'dir-symlink');
|
||||
assert.ok(fs.lstatSync(dirSymlinkPath).isDirectory());
|
||||
assert.deepEqual(fs.readdirSync(dirSymlinkPath), ['bar']);
|
||||
|
||||
cb();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('broken symlink handling', function () {
|
||||
var fixtures = path.join(__dirname, 'broken-symlink-fixtures'),
|
||||
src = path.join(fixtures, 'src'),
|
||||
out = path.join(fixtures, 'out');
|
||||
|
||||
beforeEach(function (cb) {
|
||||
rimraf(out, cb);
|
||||
});
|
||||
|
||||
it('copies broken symlinks by default', function (cb) {
|
||||
ncp(src, out, function (err) {
|
||||
if (err) return cb(err);
|
||||
assert.equal(fs.readlinkSync(path.join(out, 'broken-symlink')), 'does-not-exist');
|
||||
cb();
|
||||
})
|
||||
});
|
||||
|
||||
it('returns an error when dereference=true', function (cb) {
|
||||
ncp(src, out, {dereference: true}, function (err) {
|
||||
assert.equal(err.length, 1);
|
||||
assert.equal(err[0].code, 'ENOENT');
|
||||
cb();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('modified files copies', function () {
|
||||
var fixtures = path.join(__dirname, 'modified-files'),
|
||||
src = path.join(fixtures, 'src'),
|
||||
out = path.join(fixtures, 'out');
|
||||
|
||||
it('if file not exists copy file to target', function(cb) {
|
||||
rimraf(out, function() {
|
||||
ncp(src, out, {modified: true, clobber: false}, function (err) {
|
||||
assert.equal(fs.existsSync(out), true);
|
||||
cb();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('change source file mtime and copy', function(cb) {
|
||||
fs.utimesSync(src+"/a", new Date().getTime()/1000, new Date('2015-01-01 00:00:00').getTime()/1000);
|
||||
ncp(src, out, {modified: true, clobber: false}, function (err) {
|
||||
fs.stat(out+"/a", function(err, stats) {
|
||||
assert.equal(stats.mtime.getTime(), new Date('2015-01-01 00:00:00').getTime());
|
||||
cb();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
+1
@@ -0,0 +1 @@
|
||||
Hello world
|
||||
+1
@@ -0,0 +1 @@
|
||||
Hello ncp
|
||||
+1
@@ -0,0 +1 @@
|
||||
Hello nodejitsu
|
||||
+1
@@ -0,0 +1 @@
|
||||
bar contents
|
||||
+1
@@ -0,0 +1 @@
|
||||
foo contents
|
||||
Reference in New Issue
Block a user