blob: 22875adcd5454419313ce466cc69a827bdba7e42 [file] [log] [blame]
'use strict';
var path = require('path');
var fs = require('fs');
var glob = require('glob');
var mkdirp = require('mkdirp');
var untildify = require('untildify');
var through = require('through2').obj;
var noms = require('noms').obj;
function toStream(array) {
var length = array.length;
var i = 0;
return noms(function (done) {
if (i >= length) {
this.push(null);
}
this.push(array[i++]);
done();
});
}
function depth(string) {
return path.normalize(string).split(path.sep).length - 1;
}
function dealWith(inPath, up) {
if (!up) {
return inPath;
}
if (up === true) {
return path.basename(inPath);
}
if (depth(inPath) < up) {
throw new Error('cant go up that far');
}
return path.join.apply(path, path.normalize(inPath).split(path.sep).slice(up));
}
var copyFile = _copyFile;
function _copyFile (src, dst, opts, callback) {
fs.createReadStream(src)
.pipe(fs.createWriteStream(dst, {
mode: opts.mode
}))
.once('error', callback)
.once('finish', function () {
fs.chmod(dst, opts.mode, function (err) {
callback(err);
})
})
}
if (fs.copyFile) {
copyFile = function (src, dst, opts, callback) {
fs.copyFile(src, dst, callback);
}
}
function makeDebug(config) {
if (config.verbose) {
return function (thing) {
console.log(thing);
}
}
return function () {}
}
module.exports = copyFiles;
function copyFiles(args, config, callback) {
if (typeof config === 'function') {
callback = config;
config = {
up:0
};
}
if (typeof config !== 'object' && config) {
config = {
up: config
};
}
var debug = makeDebug(config);
var copied = false;
var opts = config.up || 0;
var soft = config.soft;
if (typeof callback !== 'function') {
throw new Error('callback is not optional');
}
var input = args.slice();
var outDir = input.pop();
var globOpts = {};
if (config.exclude) {
globOpts.ignore = config.exclude;
}
if (config.all) {
globOpts.dot = true;
}
if (config.follow) {
globOpts.follow = true;
}
outDir = outDir.startsWith('~') ? untildify(outDir) : outDir;
toStream(input.map(function(srcP) {return srcP.startsWith('~') ? untildify(srcP) : srcP;}))
.pipe(through(function (pathName, _, next) {
var self = this;
glob(pathName, globOpts, function (err, paths) {
if (err) {
return next(err);
}
paths.forEach(function (unglobbedPath) {
debug(`unglobed path: ${unglobbedPath}`);
self.push(unglobbedPath);
});
next();
});
}))
.on('error', callback)
.pipe(through(function (pathName, _, next) {
fs.stat(pathName, function (err, pathStat) {
if (err) {
return next(err);
}
var outName = path.join(outDir, dealWith(pathName, opts));
function done(){
mkdirp(path.dirname(outName)).then(()=>{
next(null, {
pathName: pathName,
pathStat: pathStat
});
}, next);
}
if (pathStat.isDirectory()) {
debug(`skipping, is directory: ${pathName}`)
return next();
}
if (!pathStat.isFile()) {
return next(new Error('how can it be neither file nor folder?'))
}
if (!soft) {
return done();
}
fs.stat(outName, function(err){
if(!err){
//file exists
return next()
}
if (err.code === 'ENOENT') {
//file does not exist
return done();
}
// other error
return next(err)
})
});
}))
.on('error', callback)
.pipe(through(function (obj, _, next) {
if (!copied) {
copied = true;
}
var pathName = obj.pathName;
var pathStat = obj.pathStat;
var outName = path.join(outDir, dealWith(pathName, opts));
debug(`copy from: ${pathName}`)
debug(`copy to: ${outName}`)
copyFile(pathName, outName, pathStat, next)
}))
.on('error', callback)
.on('finish', function () {
if (config.error && !copied) {
return callback(new Error('nothing coppied'));
}
callback();
});
}