168 lines
4.0 KiB
JavaScript
Executable File
168 lines
4.0 KiB
JavaScript
Executable File
'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();
|
|
});
|
|
}
|