fix
This commit is contained in:
342
book/node_modules/cpr/lib/index.js
generated
vendored
Normal file
342
book/node_modules/cpr/lib/index.js
generated
vendored
Normal file
@ -0,0 +1,342 @@
|
||||
/*
|
||||
Copyright (c) 2012, Yahoo! Inc. All rights reserved.
|
||||
Code licensed under the BSD License:
|
||||
http://yuilibrary.com/license/
|
||||
*/
|
||||
var fs = require('graceful-fs');
|
||||
var Stack = require('./stack').Stack;
|
||||
var path = require('path');
|
||||
var rimraf = require('rimraf');
|
||||
var mkdirp = require('mkdirp');
|
||||
|
||||
var getTree = function(from, options, callback) {
|
||||
var stack = new Stack(),
|
||||
errors = [],
|
||||
results = {};
|
||||
|
||||
options.stats = options.stats || {};
|
||||
options.toHash = options.toHash || {};
|
||||
|
||||
fs.readdir(from, stack.add(function(err, dirs) {
|
||||
if (!dirs.length) {
|
||||
results[from] = true;
|
||||
fs.stat(from, stack.add(function(err, stat) {
|
||||
/*istanbul ignore next*/
|
||||
if (err) {
|
||||
return errors.push(err);
|
||||
}
|
||||
options.stats[from] = stat;
|
||||
options.toHash[from] = path.join(options.to, path.relative(options.from, from));
|
||||
}));
|
||||
}
|
||||
dirs.forEach(function (dir) {
|
||||
var base = path.join(from, dir);
|
||||
fs.stat(base, stack.add(function(err, stat) {
|
||||
options.stats[base] = stat;
|
||||
options.toHash[base] = path.join(options.to, path.relative(options.from, base));
|
||||
/*istanbul ignore next*/
|
||||
if (err) {
|
||||
return errors.push(err);
|
||||
}
|
||||
if (stat.isDirectory()) {
|
||||
getTree(base, options, stack.add(function(errs, tree) {
|
||||
/*istanbul ignore next*/
|
||||
if (errs && errs.length) {
|
||||
errs.forEach(function(item) {
|
||||
errors.push(item);
|
||||
});
|
||||
}
|
||||
//tree is always an Array
|
||||
tree.forEach(function(item) {
|
||||
results[item] = true;
|
||||
});
|
||||
}));
|
||||
} else {
|
||||
results[base] = true;
|
||||
}
|
||||
}));
|
||||
});
|
||||
}));
|
||||
|
||||
stack.done(function() {
|
||||
callback(errors, Object.keys(results).sort());
|
||||
});
|
||||
};
|
||||
|
||||
var filterTree = function (tree, options, callback) {
|
||||
var t = tree;
|
||||
if (options.filter) {
|
||||
if (typeof options.filter === 'function') {
|
||||
t = tree.filter(options.filter);
|
||||
} else if (options.filter instanceof RegExp) {
|
||||
t = tree.filter(function(item) {
|
||||
return !options.filter.test(item);
|
||||
});
|
||||
}
|
||||
}
|
||||
callback(null, t);
|
||||
};
|
||||
|
||||
var splitTree = function (tree, options, callback) {
|
||||
var files = {},
|
||||
dirs = {};
|
||||
|
||||
tree.forEach(function(item) {
|
||||
var to = options.toHash[item];
|
||||
if (options.stats[item] && options.stats[item].isDirectory()) {
|
||||
dirs[item] = true;
|
||||
} else {
|
||||
dirs[path.dirname(item)] = true;
|
||||
options.stats[path.dirname(item)] = fs.statSync(path.dirname(item));
|
||||
options.toHash[path.dirname(item)] = path.dirname(to);
|
||||
}
|
||||
});
|
||||
|
||||
tree.forEach(function(item) {
|
||||
if (!dirs[item]) {
|
||||
files[item] = true;
|
||||
}
|
||||
});
|
||||
|
||||
callback(Object.keys(dirs).sort(), Object.keys(files).sort());
|
||||
};
|
||||
|
||||
|
||||
var createDirs = function(dirs, to, options, callback) {
|
||||
var stack = new Stack();
|
||||
|
||||
dirs.forEach(function(dir) {
|
||||
var stat = options.stats[dir],
|
||||
to = options.toHash[dir];
|
||||
|
||||
/*istanbul ignore else*/
|
||||
if (to && typeof to === 'string') {
|
||||
fs.stat(to, stack.add(function(err, s) {
|
||||
if (s && !s.isDirectory()) {
|
||||
/*istanbul ignore next*/
|
||||
err = new Error(to + ' exists and is not a directory, can not create');
|
||||
/*istanbul ignore next*/
|
||||
err.code = 'ENOTDIR';
|
||||
/*istanbul ignore next*/
|
||||
err.errno = 27;
|
||||
options.errors.push(err);
|
||||
} else {
|
||||
mkdirp(to, stat.mode, stack.add(function(err) {
|
||||
/*istanbul ignore next*/
|
||||
if (err) {
|
||||
options.errors.push(err);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
stack.done(function() {
|
||||
callback();
|
||||
});
|
||||
};
|
||||
|
||||
var copyFile = function(from, to, options, callback) {
|
||||
var dir = path.dirname(to);
|
||||
mkdirp(dir, function() {
|
||||
fs.stat(to, function(statError) {
|
||||
var err;
|
||||
if(!statError && options.overwrite !== true) {
|
||||
/*istanbul ignore next*/
|
||||
err = new Error('File '+to+' exists');
|
||||
/*istanbul ignore next*/
|
||||
err.code = 'EEXIST';
|
||||
/*istanbul ignore next*/
|
||||
err.errno = 47;
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
var fromFile = fs.createReadStream(from),
|
||||
toFile = fs.createWriteStream(to, {
|
||||
mode: options.stats[from].mode
|
||||
}),
|
||||
called = false,
|
||||
cb = function(e) {
|
||||
/*istanbul ignore next - This catches a hard to trap race condition */
|
||||
if (!called) {
|
||||
callback(e);
|
||||
called = true;
|
||||
}
|
||||
},
|
||||
/*istanbul ignore next*/
|
||||
onError = function (e) {
|
||||
err = e;
|
||||
cb(e);
|
||||
};
|
||||
|
||||
fromFile.on('error', onError);
|
||||
toFile.on('error', onError);
|
||||
toFile.once('finish', function() {
|
||||
cb(err);
|
||||
});
|
||||
fromFile.pipe(toFile);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var createFiles = function(files, to, options, callback) {
|
||||
var next = process.nextTick,
|
||||
complete = 0,
|
||||
count = files.length,
|
||||
check = function() {
|
||||
/*istanbul ignore else - Shouldn't need this if graceful-fs does it's job*/
|
||||
if (count === complete) {
|
||||
callback();
|
||||
}
|
||||
},
|
||||
copy = function() {
|
||||
var from = files.pop(),
|
||||
to = options.toHash[from],
|
||||
bail;
|
||||
if (!from) {
|
||||
return check();
|
||||
}
|
||||
copyFile(from, to, options, function(err) {
|
||||
/*istanbul ignore next*/
|
||||
//This shouldn't happen with graceful-fs, but just in case
|
||||
if (/EMFILE/.test(err)) {
|
||||
bail = true;
|
||||
files.push(from);
|
||||
} else if (err) {
|
||||
options.errors.push(err);
|
||||
}
|
||||
/*istanbul ignore next*/
|
||||
if (!bail) {
|
||||
complete++;
|
||||
}
|
||||
next(copy);
|
||||
});
|
||||
};
|
||||
|
||||
copy();
|
||||
};
|
||||
|
||||
var confirm = function(files, options, callback) {
|
||||
var stack = new Stack(),
|
||||
errors = [],
|
||||
f = [],
|
||||
filtered = files;
|
||||
|
||||
if (options.filter) {
|
||||
if (typeof options.filter === 'function') {
|
||||
filtered = files.filter(options.filter);
|
||||
} else if (options.filter instanceof RegExp) {
|
||||
filtered = files.filter(function(item) {
|
||||
return !options.filter.test(item);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*istanbul ignore else - filtered should be an array, but just in case*/
|
||||
if (filtered.length) {
|
||||
filtered.forEach(function(file) {
|
||||
fs.stat(file, stack.add(function(err, stat) {
|
||||
/*istanbul ignore next*/
|
||||
if (err) {
|
||||
errors.push(err);
|
||||
} else {
|
||||
if (stat && (stat.isFile() || stat.isDirectory())) {
|
||||
f.push(file);
|
||||
}
|
||||
}
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
stack.done(function() {
|
||||
/*istanbul ignore next */
|
||||
callback(((errors.length) ? errors : null), f.sort());
|
||||
});
|
||||
};
|
||||
|
||||
var cpr = function(from, to, opts, callback) {
|
||||
if (typeof opts === 'function') {
|
||||
callback = opts;
|
||||
opts = {};
|
||||
}
|
||||
|
||||
var options = {},
|
||||
proc;
|
||||
|
||||
/*istanbul ignore next - in case a callback isn't provided*/
|
||||
callback = callback || function () {};
|
||||
|
||||
Object.keys(opts).forEach(function(key) {
|
||||
options[key] = opts[key];
|
||||
});
|
||||
|
||||
options.from = from;
|
||||
options.to = to;
|
||||
options.errors = [];
|
||||
|
||||
proc = function() {
|
||||
getTree(options.from, options, function(err, tree) {
|
||||
filterTree(tree, options, function(err, t) {
|
||||
splitTree(t, options, function(dirs, files) {
|
||||
if (!dirs.length && !files.length) {
|
||||
return callback(new Error('No files to copy'));
|
||||
}
|
||||
createDirs(dirs, to, options, function() {
|
||||
createFiles(files, to, options, function() {
|
||||
var out = [], err;
|
||||
Object.keys(options.toHash).forEach(function(k) {
|
||||
out.push(options.toHash[k]);
|
||||
});
|
||||
if (options.confirm) {
|
||||
confirm(out, options, callback);
|
||||
} else if (!options.errors.length) {
|
||||
callback(null, out.sort());
|
||||
} else {
|
||||
/*istanbul ignore next*/
|
||||
err = new Error('Unable to copy directory' + (out.length ? ' entirely' : ''));
|
||||
/*istanbul ignore next*/
|
||||
err.list = options.errors;
|
||||
/*istanbul ignore next*/
|
||||
callback(err, out.sort());
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
fs.stat(options.from, function(err, stat) {
|
||||
if (err) {
|
||||
return callback(new Error('From should be a file or directory'));
|
||||
}
|
||||
if (stat && stat.isDirectory()) {
|
||||
if (options.deleteFirst) {
|
||||
rimraf(to, function() {
|
||||
proc();
|
||||
});
|
||||
} else {
|
||||
proc();
|
||||
|
||||
}
|
||||
} else {
|
||||
if (stat.isFile()) {
|
||||
var dirRegex = new RegExp(path.sep + '$');
|
||||
if (dirRegex.test(to)) { // Create directory if has trailing separator
|
||||
to = path.join(to, path.basename(options.from));
|
||||
}
|
||||
// ensure copyFile() can access cached stat
|
||||
options.stats = options.stats || {};
|
||||
options.stats[from] = stat;
|
||||
return copyFile(options.from, to, options, callback);
|
||||
}
|
||||
callback(new Error('From should be a file or directory'));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
//Preserve backward compatibility
|
||||
cpr.cpr = cpr;
|
||||
//Export a function
|
||||
module.exports = cpr;
|
44
book/node_modules/cpr/lib/stack.js
generated
vendored
Normal file
44
book/node_modules/cpr/lib/stack.js
generated
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
Copyright (c) 2012, Yahoo! Inc. All rights reserved.
|
||||
Code licensed under the BSD License:
|
||||
http://yuilibrary.com/license/
|
||||
*/
|
||||
var Stack = function () {
|
||||
this.errors = [];
|
||||
this.finished = 0;
|
||||
this.results = [];
|
||||
this.total = 0;
|
||||
};
|
||||
|
||||
Stack.prototype = {
|
||||
add: function (fn) {
|
||||
var self = this,
|
||||
index = self.total;
|
||||
|
||||
self.total += 1;
|
||||
|
||||
return function (err) {
|
||||
if (err) { self.errors[index] = err; }
|
||||
|
||||
self.finished += 1;
|
||||
self.results[index] = fn.apply(null, arguments);
|
||||
self.test();
|
||||
};
|
||||
},
|
||||
|
||||
test: function () {
|
||||
if (this.finished >= this.total && this.callback) {
|
||||
this.callback.call(null, this.errors.length ? this.errors : null,
|
||||
this.results, this.data);
|
||||
}
|
||||
},
|
||||
|
||||
done: function (callback, data) {
|
||||
this.callback = callback;
|
||||
this.data = data;
|
||||
this.test();
|
||||
}
|
||||
};
|
||||
|
||||
exports.Stack = Stack;
|
||||
|
Reference in New Issue
Block a user